diff --git a/README.md b/README.md index 3a4ea69..836eb4b 100755 --- a/README.md +++ b/README.md @@ -7,20 +7,24 @@ The aim of this project is to help users to use the RAK Raspberry Pi Developer G ## Supported platforms This project currently provides support for the below platforms. -* RAK831 +* RAK831(Choose RAK2245) * RAK2245 * RAK7243/RAK7244 no LTE * RAK7243/RAK7244 with LTE -* RAK833(USB) +* RAK833(USB)(Choose RAK2247 USB) * RAK2247(USB) -* RAK833(SPI) +* RAK833(SPI)(Choose RAK2247 SPI) * RAK2247(SPI) * RAK2246 * RAK7248 no LTE (RAK2287 + raspberry pi) * RAK7248 with LTE (RAK2287 + LTE + raspberry pi) -* RAK2285 ## Changelog +2021-03-09 V4.2.8 + +* 1.Added support for RAK2287-USB. +* 2.Remove some obsolete models. + 2021-01-21 V4.2.7 * 1.Only upgraded for RAK2287, added EU433 and CN470 for RAK2287. @@ -107,19 +111,16 @@ step3 : Clone the installer and start the installation (More installation option step4 : Next you will see some messages as follow. Please select the corresponding hardware model. Please select your gateway model: - * 1.RAK831 - * 2.RAK2245 - * 3.RAK7243/RAK7244 no LTE - * 4.RAK7243/RAK7244 with LTE - * 5.RAK833(USB) - * 6.RAK2247(USB) - * 7.RAK833(SPI) - * 8.RAK2247(SPI) - * 9.RAK2246 - * 10.RAK7248 no LTE (RAK2287 + raspberry pi) - * 11.RAK7248 with LTE (RAK2287 + LTE + raspberry pi) - * 12.RAK2285 - Please enter 1-12 to select the model: + * 1.RAK2245 + * 2.RAK7243/RAK7244 no LTE + * 3.RAK7243/RAK7244 with LTE + * 4.RAK2247(USB) + * 5.RAK2247(SPI) + * 6.RAK2246 + * 7.RAK7248 no LTE (RAK2287 SPI + raspberry pi) + * 8.RAK7248 with LTE (RAK2287 SPI + LTE + raspberry pi) + * 9.RAK2287 USB + Please enter 1-9 to select the model: step5 : Wait a moment and the installation is complete. diff --git a/chirpstack/install.sh b/chirpstack/install.sh index 9e22f5a..d2f0234 100755 --- a/chirpstack/install.sh +++ b/chirpstack/install.sh @@ -36,7 +36,7 @@ sudo -u postgres psql -c "create database chirpstack_as with owner chirpstack_as sudo -u postgres psql -c "create database chirpstack_ns with owner chirpstack_ns;" sudo -u postgres psql chirpstack_as -c "create extension pg_trgm;" sudo -u postgres psql chirpstack_as -c "create extension hstore;" -sudo -u postgres psql -U postgres -f /tmp/init_sql.sql +#sudo -u postgres psql -U postgres -f /tmp/init_sql.sql rm -f /tmp/init_sql.sql #3. install lora packages diff --git a/choose_model.sh b/choose_model.sh index 5d816b3..e364c79 100755 --- a/choose_model.sh +++ b/choose_model.sh @@ -39,19 +39,16 @@ do_check_variable_type_echo(){ function echo_model_info() { echo_yellow "Please select your gateway model:" - echo_yellow "*\t 1.RAK831" - echo_yellow "*\t 2.RAK2245" - echo_yellow "*\t 3.RAK7243/RAK7244 no LTE" - echo_yellow "*\t 4.RAK7243/RAK7244 with LTE" - echo_yellow "*\t 5.RAK833(USB)" - echo_yellow "*\t 6.RAK2247(USB)" - echo_yellow "*\t 7.RAK833(SPI)" - echo_yellow "*\t 8.RAK2247(SPI)" - echo_yellow "*\t 9.RAK2246" - echo_yellow "*\t10.RAK7248 no LTE (RAK2287 + raspberry pi)" - echo_yellow "*\t11.RAK7248 with LTE (RAK2287 + LTE + raspberry pi)" - echo_yellow "*\t12.RAK2285" - echo_yellow "Please enter 1-12 to select the model:\c" + echo_yellow "*\t 1.RAK2245" + echo_yellow "*\t 2.RAK7243/RAK7244 no LTE" + echo_yellow "*\t 3.RAK7243/RAK7244 with LTE" + echo_yellow "*\t 4.RAK2247(USB)" + echo_yellow "*\t 5.RAK2247(SPI)" + echo_yellow "*\t 6.RAK2246" + echo_yellow "*\t 7.RAK7248 no LTE (RAK2287 SPI + raspberry pi)" + echo_yellow "*\t 8.RAK7248 with LTE (RAK2287 SPI + LTE + raspberry pi)" + echo_yellow "*\t 9.RAK2287 USB" + echo_yellow "Please enter 1-9 to select the model:\c" } function do_set_model_to_json() @@ -60,19 +57,16 @@ function do_set_model_to_json() RAK_GW_JSON=./rak/rak/gateway-config-info.json INSTALL_LTE=0 if [ $1 -eq 1 ]; then - GW_MODEL=RAK831 - do_set_spi_to_json 1 - elif [ $1 -eq 2 ]; then GW_MODEL=RAK2245 do_set_spi_to_json 1 - elif [ $1 -eq 3 ]; then + elif [ $1 -eq 2 ]; then if [ $rpi_model -eq 4 ]; then GW_MODEL=RAK7244 else GW_MODEL=RAK7243 fi do_set_spi_to_json 1 - elif [ $1 -eq 4 ]; then + elif [ $1 -eq 3 ]; then if [ $rpi_model -eq 4 ]; then GW_MODEL=RAK7244 else @@ -80,31 +74,25 @@ function do_set_model_to_json() fi INSTALL_LTE=1 do_set_spi_to_json 1 - elif [ $1 -eq 5 ]; then - GW_MODEL=RAK833 - do_set_spi_to_json 0 - elif [ $1 -eq 6 ]; then + elif [ $1 -eq 4 ]; then GW_MODEL=RAK2247 do_set_spi_to_json 0 - elif [ $1 -eq 7 ]; then - GW_MODEL=RAK833 - do_set_spi_to_json 1 - elif [ $1 -eq 8 ]; then + elif [ $1 -eq 5 ]; then GW_MODEL=RAK2247 do_set_spi_to_json 1 - elif [ $1 -eq 9 ]; then + elif [ $1 -eq 6 ]; then GW_MODEL=RAK2246 do_set_spi_to_json 1 - elif [ $1 -eq 10 ]; then + elif [ $1 -eq 7 ]; then GW_MODEL=RAK7248 do_set_spi_to_json 1 - elif [ $1 -eq 11 ]; then + elif [ $1 -eq 8 ]; then GW_MODEL=RAK7248 do_set_spi_to_json 1 INSTALL_LTE=1 - elif [ $1 -eq 12 ]; then - GW_MODEL=RAK2285 - do_set_spi_to_json 1 + elif [ $1 -eq 9 ]; then + GW_MODEL=RAK2287 + do_set_spi_to_json 0 else # Never come here echo "error" @@ -133,7 +121,7 @@ function do_set_model() do read RAK_MODEL if [ -z "$RAK_MODEL" ]; then - echo_yellow "Please enter 1-12 to select the model:\c" + echo_yellow "Please enter 1-9 to select the model:\c" continue fi @@ -141,7 +129,7 @@ function do_set_model() RET=$? if [ $RET -eq 0 ]; then - if [ $RAK_MODEL -lt 1 ] || [ $RAK_MODEL -gt 12 ]; then + if [ $RAK_MODEL -lt 1 ] || [ $RAK_MODEL -gt 9 ]; then echo_yellow "Please enter 1-10 to select the model:\c" continue else @@ -149,7 +137,7 @@ function do_set_model() return 0 fi else - echo_yellow "Please enter 1-12 to select the model:\c" + echo_yellow "Please enter 1-9 to select the model:\c" continue fi diff --git a/lora/install_for_img.sh b/lora/install_for_img.sh index d861750..c21cefc 100755 --- a/lora/install_for_img.sh +++ b/lora/install_for_img.sh @@ -20,10 +20,6 @@ pushd rak7243 ./install.sh popd -pushd rak2245 -./install.sh -popd - pushd rak2246 ./install.sh popd @@ -36,23 +32,14 @@ pushd rak2247_spi ./install.sh popd -pushd rak2287_spi +pushd rak2287 ./install.sh popd -pushd rak2285 -./install.sh -popd - - cp ./update_gwid.sh rak7243/packet_forwarder/lora_pkt_fwd/update_gwid.sh cp ./start.sh rak7243/packet_forwarder/lora_pkt_fwd/start.sh cp ./set_eui.sh rak7243/packet_forwarder/lora_pkt_fwd/set_eui.sh -cp ./update_gwid.sh rak2245/packet_forwarder/lora_pkt_fwd/update_gwid.sh -cp ./start.sh rak2245/packet_forwarder/lora_pkt_fwd/start.sh -cp ./set_eui.sh rak2245/packet_forwarder/lora_pkt_fwd/set_eui.sh - cp ./update_gwid.sh rak2246/packet_forwarder/lora_pkt_fwd/update_gwid.sh cp ./start.sh rak2246/packet_forwarder/lora_pkt_fwd/start.sh cp ./set_eui.sh rak2246/packet_forwarder/lora_pkt_fwd/set_eui.sh @@ -65,21 +52,15 @@ cp ./update_gwid.sh rak2247_spi/packet_forwarder/lora_pkt_fwd/update_gwid.sh cp ./start.sh rak2247_spi/packet_forwarder/lora_pkt_fwd/start.sh cp ./set_eui.sh rak2247_spi/packet_forwarder/lora_pkt_fwd/set_eui.sh -cp ./update_gwid.sh rak2287_spi/packet_forwarder/lora_pkt_fwd/update_gwid.sh -cp ./start.sh rak2287_spi/packet_forwarder/lora_pkt_fwd/start.sh -cp ./set_eui.sh rak2287_spi/packet_forwarder/lora_pkt_fwd/set_eui.sh - -cp ./update_gwid.sh rak2285/packet_forwarder/lora_pkt_fwd/update_gwid.sh -cp ./start.sh rak2285/packet_forwarder/lora_pkt_fwd/start.sh -cp ./set_eui.sh rak2285/packet_forwarder/lora_pkt_fwd/set_eui.sh +cp ./update_gwid.sh rak2287/packet_forwarder/lora_pkt_fwd/update_gwid.sh +cp ./start.sh rak2287/packet_forwarder/lora_pkt_fwd/start.sh +cp ./set_eui.sh rak2287/packet_forwarder/lora_pkt_fwd/set_eui.sh cp rak7243 /usr/local/rak/lora/ -rf -cp rak2245 /usr/local/rak/lora/ -rf cp rak2246 /usr/local/rak/lora/ -rf cp rak2247_usb /usr/local/rak/lora/ -rf cp rak2247_spi /usr/local/rak/lora/ -rf -cp rak2287_spi /usr/local/rak/lora/ -rf -cp rak2285 /usr/local/rak/lora/ -rf +cp rak2287 /usr/local/rak/lora/ -rf cp ttn-gateway.service /lib/systemd/system/ttn-gateway.service diff --git a/lora/install_normal.sh b/lora/install_normal.sh index 49e6ba2..4ba28a9 100755 --- a/lora/install_normal.sh +++ b/lora/install_normal.sh @@ -21,7 +21,7 @@ INSTALL_LTE=`do_get_gw_install_lte` mkdir /opt/ttn-gateway -p -if [ "${RAK_GW_MODEL}" = "RAK2247" ] || [ "${RAK_GW_MODEL}" = "RAK833" ]; then +if [ "${RAK_GW_MODEL}" = "RAK2247" ]; then if [ "${LORA_SPI}" = "1" ]; then pushd rak2247_spi ./install.sh @@ -33,14 +33,18 @@ if [ "${RAK_GW_MODEL}" = "RAK2247" ] || [ "${RAK_GW_MODEL}" = "RAK833" ]; then fi popd elif [ "${RAK_GW_MODEL}" = "RAK2287" ] ; then - pushd rak2287_spi - if [ "${INSTALL_LTE}" = "1" ]; then - cp global_conf_i2c global_conf -rf + pushd rak2287 + if [ "${LORA_SPI}" = "1" ]; then + if [ "${INSTALL_LTE}" = "1" ]; then + cp global_conf_i2c global_conf -rf + else + cp global_conf_uart global_conf -rf + fi else - cp global_conf_uart global_conf -rf + cp global_conf_usb global_conf -rf fi ./install.sh - LORA_DIR_TMP=rak2287_spi + LORA_DIR_TMP=rak2287 popd elif [ "${RAK_GW_MODEL}" = "RAK7243" ] || [ "${RAK_GW_MODEL}" = "RAK7244" ]; then pushd rak7243 @@ -51,13 +55,6 @@ elif [ "${RAK_GW_MODEL}" = "RAK7243" ] || [ "${RAK_GW_MODEL}" = "RAK7244" ]; the fi ./install.sh LORA_DIR_TMP=rak7243 - popd -elif [ "${RAK_GW_MODEL}" = "RAK2285" ]; then - - pushd rak2285 - LORA_DIR_TMP=rak2285 - ./install.sh - popd else if [ "${RAK_GW_MODEL}" = "RAK2246" ]; then diff --git a/lora/rak2245/global_conf/global_conf.as_920_923.json b/lora/rak2245/global_conf/global_conf.as_920_923.json deleted file mode 100755 index e89b4b0..0000000 --- a/lora/rak2245/global_conf/global_conf.as_920_923.json +++ /dev/null @@ -1,197 +0,0 @@ -{ - "gateway_conf":{ - "gateway_ID":"0000000000000000", - "server_address":"router.as2.thethings.network", - "serv_port_up":1700, - "serv_port_down":1700, - "forward_crc_disabled":false, - "forward_crc_error":false, - "forward_crc_valid":true, - "keepalive_interval":10, - "stat_interval":30, - "push_timeout_ms":100, - "fake_gps":false, - "autoquit_threshold":30, - "gps_tty_path":"/dev/ttyAMA0", - "beacon_period": 0, /* disable class B beacon */ - "beacon_freq_hz": 923400000, - "beacon_freq_nb": 1, - "beacon_freq_step": 0, - "beacon_datarate": 9, - "beacon_bw_hz": 125000, - "beacon_power": 27 - - }, - "SX1301_conf": - { - "lorawan_public":true, - "clksrc":1, - "antenna_gain":0, - "radio_0":{ - "enable":true, - "type":"SX1257", - "freq":923000000, - "rssi_offset":-166, - "tx_enable":true, - "tx_freq_min":921800000, - "tx_freq_max":923600000 - }, - "radio_1":{ - "enable":true, - "type":"SX1257", - "freq":922000000, - "rssi_offset":-166, - "tx_enable":false - }, - "chan_multiSF_0":{ - "enable":true, - "radio":0, - "if":200000 - }, - "chan_multiSF_1":{ - "enable":true, - "radio":0, - "if":400000 - }, - "chan_multiSF_2":{ - "enable":true, - "radio":1, - "if":200000 - }, - "chan_multiSF_3":{ - "enable":true, - "radio":1, - "if":400000 - }, - "chan_multiSF_4":{ - "enable":true, - "radio":0, - "if":-400000 - }, - "chan_multiSF_5":{ - "enable":true, - "radio":0, - "if":-200000 - }, - "chan_multiSF_6":{ - "enable":true, - "radio":1, - "if":0 - }, - "chan_multiSF_7":{ - "enable":true, - "radio":0, - "if":0 - }, - "chan_Lora_std":{ - "enable":true, - "radio":1, - "if":100000, - "bandwidth":250000, - "spread_factor":7 - }, - "chan_FSK":{ - "enable":true, - "radio":1, - "if":-200000, - "bandwidth":125000, - "datarate":50000 - }, - "tx_lut_0":{ - "pa_gain":0, - "mix_gain":9, - "rf_power":-6, - "dig_gain":0 - }, - "tx_lut_1":{ - "pa_gain":0, - "mix_gain":11, - "rf_power":-3, - "dig_gain":0 - }, - "tx_lut_2":{ - "pa_gain":0, - "mix_gain":15, - "rf_power":0, - "dig_gain":0 - }, - "tx_lut_3":{ - "pa_gain":1, - "mix_gain":8, - "rf_power":3, - "dig_gain":0 - }, - "tx_lut_4":{ - "pa_gain":1, - "mix_gain":10, - "rf_power":6, - "dig_gain":0 - }, - "tx_lut_5":{ - "pa_gain":1, - "mix_gain":13, - "rf_power":10, - "dig_gain": 1 - }, - "tx_lut_6":{ - "pa_gain":1, - "mix_gain":14, - "rf_power":11, - "dig_gain":0 - }, - "tx_lut_7":{ - "pa_gain":2, - "mix_gain":10, - "rf_power":12, - "dig_gain":0 - }, - "tx_lut_8":{ - "pa_gain":2, - "mix_gain":10, - "rf_power":13, - "dig_gain":0 - }, - "tx_lut_9":{ - "pa_gain":2, - "mix_gain":11, - "rf_power":14, - "dig_gain": 1 - }, - "tx_lut_10":{ - "pa_gain":2, - "mix_gain": 12, - "rf_power":16, - "dig_gain":0 - }, - "tx_lut_11":{ - "pa_gain":3, - "mix_gain":9, - "rf_power":20, - "dig_gain": 1 - }, - "tx_lut_12":{ - "pa_gain":3, - "mix_gain":11, - "rf_power":23, - "dig_gain": 1 - }, - "tx_lut_13":{ - "pa_gain":3, - "mix_gain":12, - "rf_power":25, - "dig_gain": 1 - }, - "tx_lut_14":{ - "pa_gain":3, - "mix_gain":13, - "rf_power":26, - "dig_gain": 1 - }, - "tx_lut_15":{ - "pa_gain":3, - "mix_gain":13, - "rf_power":27, - "dig_gain":0 - } - } -} diff --git a/lora/rak2245/global_conf/global_conf.as_923_925.json b/lora/rak2245/global_conf/global_conf.as_923_925.json deleted file mode 100755 index cedd1f2..0000000 --- a/lora/rak2245/global_conf/global_conf.as_923_925.json +++ /dev/null @@ -1,231 +0,0 @@ -{ - "SX1301_conf": { - "lorawan_public": true, - "clksrc": 1, - "clksrc_desc": "radio_1 provides clock to concentrator for most devices except MultiTech. For MultiTech set to 0.", - "antenna_gain": 0, - "antenna_gain_desc": "antenna gain, in dBi", - "radio_0": { - "enable": true, - "type": "SX1257", - "freq": 923600000, - "rssi_offset": -166.0, - "tx_enable": true, - "tx_freq_min": 923200000, - "tx_freq_max": 925000000 - }, - "radio_1": { - "enable": true, - "type": "SX1257", - "freq": 924600000, - "rssi_offset": -166.0, - "tx_enable": false - }, - "chan_multiSF_0": { - "desc": "Lora MAC, 125kHz, all SF, 923.2 MHz", - "enable": true, - "radio": 0, - "if": -400000 - }, - "chan_multiSF_1": { - "desc": "Lora MAC, 125kHz, all SF, 923.4 MHz", - "enable": true, - "radio": 0, - "if": -200000 - }, - "chan_multiSF_2": { - "desc": "Lora MAC, 125kHz, all SF, 923.6 MHz", - "enable": true, - "radio": 0, - "if": 0 - }, - "chan_multiSF_3": { - "desc": "Lora MAC, 125kHz, all SF, 923.8 MHz", - "enable": true, - "radio": 0, - "if": 200000 - }, - "chan_multiSF_4": { - "desc": "Lora MAC, 125kHz, all SF, 924.0 MHz", - "enable": true, - "radio": 0, - "if": 400000 - }, - "chan_multiSF_5": { - "desc": "Lora MAC, 125kHz, all SF, 924.2 MHz", - "enable": true, - "radio": 1, - "if": -400000 - }, - "chan_multiSF_6": { - "desc": "Lora MAC, 125kHz, all SF, 924.4 MHz", - "enable": true, - "radio": 1, - "if": -200000 - }, - "chan_multiSF_7": { - "desc": "Lora MAC, 125kHz, all SF, 924.6 MHz", - "enable": true, - "radio": 1, - "if": 0 - }, - "chan_Lora_std": { - "desc": "Lora MAC, 250kHz, SF7, 924.5 MHz", - "enable": true, - "radio": 1, - "if": -100000, - "bandwidth": 250000, - "spread_factor": 7 - }, - "chan_FSK": { - "desc": "FSK 50kbps, 924.8 MHz", - "enable": true, - "radio": 1, - "if": 200000, - "bandwidth": 125000, - "datarate": 50000 - }, - "tx_lut_0": { - "desc": "TX gain table, index 0", - "pa_gain": 0, - "mix_gain": 9, - "rf_power": -6, - "dig_gain": 0 - }, - "tx_lut_1": { - "desc": "TX gain table, index 1", - "pa_gain": 0, - "mix_gain": 11, - "rf_power": -3, - "dig_gain": 0 - }, - "tx_lut_2": { - "desc": "TX gain table, index 2", - "pa_gain": 0, - "mix_gain": 15, - "rf_power": 0, - "dig_gain": 0 - }, - "tx_lut_3": { - "desc": "TX gain table, index 3", - "pa_gain": 1, - "mix_gain": 8, - "rf_power": 3, - "dig_gain": 0 - }, - "tx_lut_4": { - "desc": "TX gain table, index 4", - "pa_gain": 1, - "mix_gain": 10, - "rf_power": 6, - "dig_gain": 0 - }, - "tx_lut_5": { - "desc": "TX gain table, index 5", - "pa_gain": 1, - "mix_gain": 13, - "rf_power": 10, - "dig_gain": 1 - }, - "tx_lut_6": { - "desc": "TX gain table, index 6", - "pa_gain": 1, - "mix_gain": 14, - "rf_power": 11, - "dig_gain": 0 - }, - "tx_lut_7": { - "desc": "TX gain table, index 7", - "pa_gain": 2, - "mix_gain": 10, - "rf_power": 12, - "dig_gain": 0 - }, - "tx_lut_8": { - "desc": "TX gain table, index 8", - "pa_gain": 2, - "mix_gain": 10, - "rf_power": 13, - "dig_gain": 0 - }, - "tx_lut_9": { - "desc": "TX gain table, index 9", - "pa_gain": 2, - "mix_gain": 11, - "rf_power": 14, - "dig_gain": 1 - }, - "tx_lut_10": { - "desc": "TX gain table, index 10", - "pa_gain": 2, - "mix_gain": 12, - "rf_power": 16, - "dig_gain": 0 - }, - "tx_lut_11": { - "desc": "TX gain table, index 11", - "pa_gain": 3, - "mix_gain": 9, - "rf_power": 20, - "dig_gain": 1 - }, - "tx_lut_12": { - "desc": "TX gain table, index 12", - "pa_gain": 3, - "mix_gain": 11, - "rf_power": 23, - "dig_gain": 1 - }, - "tx_lut_13": { - "desc": "TX gain table, index 13", - "pa_gain": 3, - "mix_gain": 12, - "rf_power": 25, - "dig_gain": 1 - }, - "tx_lut_14": { - "desc": "TX gain table, index 14", - "pa_gain": 3, - "mix_gain": 13, - "rf_power": 26, - "dig_gain": 1 - }, - "tx_lut_15": { - "desc": "TX gain table, index 15", - "pa_gain": 3, - "mix_gain": 13, - "rf_power": 27, - "dig_gain": 0 - } - }, - "gateway_conf": { - "gateway_ID": "0000000000000000", - /* change with default server address/ports, or overwrite in local_conf.json */ - "server_address": "router.as2.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 enable */ - "gps_tty_path": "/dev/ttyAMA0", - "fake_gps": false, - "ref_latitude": 10, - "ref_longitude": 20, - "ref_altitude": -1, - "autoquit_threshold": 20, - "beacon_period": 0, /* disable class B beacon */ - "beacon_freq_hz": 923400000, - "beacon_freq_nb": 1, - "beacon_freq_step": 0, - "beacon_datarate": 9, - "beacon_bw_hz": 125000, - "beacon_power": 27 - } - -} diff --git a/lora/rak2245/global_conf/global_conf.au_915_928.json b/lora/rak2245/global_conf/global_conf.au_915_928.json deleted file mode 100755 index b8458ae..0000000 --- a/lora/rak2245/global_conf/global_conf.au_915_928.json +++ /dev/null @@ -1,228 +0,0 @@ -{ - "SX1301_conf": { - "lorawan_public": true, - "clksrc": 1, - "clksrc_desc": "radio_1 provides clock to concentrator for most devices except MultiTech. For MultiTech set to 0.", - "antenna_gain": 0, - "antenna_gain_desc": "antenna gain, in dBi", - "radio_0": { - "enable": true, - "type": "SX1257", - "freq": 917200000, - "rssi_offset": -166.0, - "tx_enable": true, - "tx_freq_min": 915000000, - "tx_freq_max": 928000000 - }, - "radio_1": { - "enable": true, - "type": "SX1257", - "freq": 917900000, - "rssi_offset": -166.0, - "tx_enable": false - }, - "chan_multiSF_0": { - "desc": "Lora MAC, 125kHz, all SF, 916.8 MHz", - "enable": true, - "radio": 0, - "if": -400000 - }, - "chan_multiSF_1": { - "desc": "Lora MAC, 125kHz, all SF, 917.0 MHz", - "enable": true, - "radio": 0, - "if": -200000 - }, - "chan_multiSF_2": { - "desc": "Lora MAC, 125kHz, all SF, 917.2 MHz", - "enable": true, - "radio": 0, - "if": 0 - }, - "chan_multiSF_3": { - "desc": "Lora MAC, 125kHz, all SF, 917.4 MHz", - "enable": true, - "radio": 0, - "if": 200000 - }, - "chan_multiSF_4": { - "desc": "Lora MAC, 125kHz, all SF, 917.6 MHz", - "enable": true, - "radio": 1, - "if": -300000 - }, - "chan_multiSF_5": { - "desc": "Lora MAC, 125kHz, all SF, 917.8 MHz", - "enable": true, - "radio": 1, - "if": -100000 - }, - "chan_multiSF_6": { - "desc": "Lora MAC, 125kHz, all SF, 918.0 MHz", - "enable": true, - "radio": 1, - "if": 100000 - }, - "chan_multiSF_7": { - "desc": "Lora MAC, 125kHz, all SF, 918.2 MHz", - "enable": true, - "radio": 1, - "if": 300000 - }, - "chan_Lora_std": { - "desc": "Lora MAC, 500kHz, SF8, 917.5 MHz", - "enable": true, - "radio": 0, - "if": 300000, - "bandwidth": 500000, - "spread_factor": 8 - }, - "chan_FSK": { - "desc": "disabled", - "enable": false - }, - "tx_lut_0": { - "desc": "TX gain table, index 0", - "pa_gain": 0, - "mix_gain": 9, - "rf_power": -6, - "dig_gain": 0 - }, - "tx_lut_1": { - "desc": "TX gain table, index 1", - "pa_gain": 0, - "mix_gain": 11, - "rf_power": -3, - "dig_gain": 0 - }, - "tx_lut_2": { - "desc": "TX gain table, index 2", - "pa_gain": 0, - "mix_gain": 15, - "rf_power": 0, - "dig_gain": 0 - }, - "tx_lut_3": { - "desc": "TX gain table, index 3", - "pa_gain": 1, - "mix_gain": 8, - "rf_power": 3, - "dig_gain": 0 - }, - "tx_lut_4": { - "desc": "TX gain table, index 4", - "pa_gain": 1, - "mix_gain": 10, - "rf_power": 6, - "dig_gain": 0 - }, - "tx_lut_5": { - "desc": "TX gain table, index 5", - "pa_gain": 1, - "mix_gain": 13, - "rf_power": 10, - "dig_gain": 1 - }, - "tx_lut_6": { - "desc": "TX gain table, index 6", - "pa_gain": 1, - "mix_gain": 14, - "rf_power": 11, - "dig_gain": 0 - }, - "tx_lut_7": { - "desc": "TX gain table, index 7", - "pa_gain": 2, - "mix_gain": 10, - "rf_power": 12, - "dig_gain": 0 - }, - "tx_lut_8": { - "desc": "TX gain table, index 8", - "pa_gain": 2, - "mix_gain": 10, - "rf_power": 13, - "dig_gain": 0 - }, - "tx_lut_9": { - "desc": "TX gain table, index 9", - "pa_gain": 2, - "mix_gain": 11, - "rf_power": 14, - "dig_gain": 1 - }, - "tx_lut_10": { - "desc": "TX gain table, index 10", - "pa_gain": 2, - "mix_gain": 12, - "rf_power": 16, - "dig_gain": 0 - }, - "tx_lut_11": { - "desc": "TX gain table, index 11", - "pa_gain": 3, - "mix_gain": 9, - "rf_power": 20, - "dig_gain": 1 - }, - "tx_lut_12": { - "desc": "TX gain table, index 12", - "pa_gain": 3, - "mix_gain": 11, - "rf_power": 23, - "dig_gain": 1 - }, - "tx_lut_13": { - "desc": "TX gain table, index 13", - "pa_gain": 3, - "mix_gain": 12, - "rf_power": 25, - "dig_gain": 1 - }, - "tx_lut_14": { - "desc": "TX gain table, index 14", - "pa_gain": 3, - "mix_gain": 13, - "rf_power": 26, - "dig_gain": 1 - }, - "tx_lut_15": { - "desc": "TX gain table, index 15", - "pa_gain": 3, - "mix_gain": 13, - "rf_power": 27, - "dig_gain": 0 - } - }, - "gateway_conf": { - "gateway_ID": "0000000000000000", - /* change with default server address/ports, or overwrite in local_conf.json */ - "server_address": "router.au.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 enable */ - "gps_tty_path": "/dev/ttyAMA0", - "fake_gps": false, - "ref_latitude": 10, - "ref_longitude": 20, - "ref_altitude": -1, - "autoquit_threshold": 20, - "beacon_period": 0, /* disable class B beacon */ - "beacon_freq_hz": 923300000, - "beacon_freq_nb": 8, - "beacon_freq_step": 600000, - "beacon_datarate": 12, - "beacon_bw_hz": 500000, - "beacon_power": 27 - } - -} - diff --git a/lora/rak2245/global_conf/global_conf.cn_470_510.json b/lora/rak2245/global_conf/global_conf.cn_470_510.json deleted file mode 100755 index 5c125b5..0000000 --- a/lora/rak2245/global_conf/global_conf.cn_470_510.json +++ /dev/null @@ -1,223 +0,0 @@ -{ - "SX1301_conf": { - "lorawan_public": true, - "clksrc": 1, - "clksrc_desc": "radio_1 provides clock to concentrator for most devices except MultiTech. For MultiTech set to 0.", - "antenna_gain": 0, - "antenna_gain_desc": "antenna gain, in dBi", - "radio_0": { - "enable": true, - "type": "SX1255", - "freq": 486600000, - "rssi_offset": -176.0, - "tx_enable": true, - "tx_freq_min": 470000000, - "tx_freq_max": 510000000 - }, - "radio_1": { - "enable": true, - "type": "SX1255", - "freq": 487400000, - "rssi_offset": -176.0, - "tx_enable": false - }, - "chan_multiSF_0": { - "desc": "Lora MAC, 125kHz, all SF, 487.1 MHz", - "enable": true, - "radio": 1, - "if": -300000 - }, - "chan_multiSF_1": { - "desc": "Lora MAC, 125kHz, all SF, 487.3 MHz", - "enable": true, - "radio": 1, - "if": -100000 - }, - "chan_multiSF_2": { - "desc": "Lora MAC, 125kHz, all SF, 487.5 MHz", - "enable": true, - "radio": 1, - "if": 100000 - }, - "chan_multiSF_3": { - "desc": "Lora MAC, 125kHz, all SF, 487.7 MHz", - "enable": true, - "radio": 1, - "if": 300000 - }, - "chan_multiSF_4": { - "desc": "Lora MAC, 125kHz, all SF, 486.3 MHz", - "enable": true, - "radio": 0, - "if": -300000 - }, - "chan_multiSF_5": { - "desc": "Lora MAC, 125kHz, all SF, 486.5 MHz", - "enable": true, - "radio": 0, - "if": -100000 - }, - "chan_multiSF_6": { - "desc": "Lora MAC, 125kHz, all SF, 486.7 MHz", - "enable": true, - "radio": 0, - "if": 100000 - }, - "chan_multiSF_7": { - "desc": "Lora MAC, 125kHz, all SF, 486.9 MHz", - "enable": true, - "radio": 0, - "if": 300000 - }, - "chan_Lora_std": { - "desc": "disabled", - "enable": false - }, - "chan_FSK": { - "desc": "disabled", - "enable": false - }, - "tx_lut_0": { - "desc": "TX gain table, index 0", - "pa_gain": 0, - "mix_gain": 8, - "rf_power": -6, - "dig_gain": 0 - }, - "tx_lut_1": { - "desc": "TX gain table, index 1", - "pa_gain": 0, - "mix_gain": 9, - "rf_power": -3, - "dig_gain": 0 - }, - "tx_lut_2": { - "desc": "TX gain table, index 2", - "pa_gain": 0, - "mix_gain": 13, - "rf_power": 0, - "dig_gain": 0 - }, - "tx_lut_3": { - "desc": "TX gain table, index 3", - "pa_gain": 1, - "mix_gain": 8, - "rf_power": 3, - "dig_gain": 1 - }, - "tx_lut_4": { - "desc": "TX gain table, index 4", - "pa_gain": 1, - "mix_gain": 9, - "rf_power": 6, - "dig_gain": 0 - }, - "tx_lut_5": { - "desc": "TX gain table, index 5", - "pa_gain": 2, - "mix_gain": 8, - "rf_power": 10, - "dig_gain": 1 - }, - "tx_lut_6": { - "desc": "TX gain table, index 6", - "pa_gain": 2, - "mix_gain": 8, - "rf_power": 11, - "dig_gain": 0 - }, - "tx_lut_7": { - "desc": "TX gain table, index 7", - "pa_gain": 2, - "mix_gain": 9, - "rf_power": 12, - "dig_gain": 1 - }, - "tx_lut_8": { - "desc": "TX gain table, index 8", - "pa_gain": 2, - "mix_gain": 9, - "rf_power": 13, - "dig_gain": 0 - }, - "tx_lut_9": { - "desc": "TX gain table, index 9", - "pa_gain": 2, - "mix_gain": 11, - "rf_power": 14, - "dig_gain": 2 - }, - "tx_lut_10": { - "desc": "TX gain table, index 10", - "pa_gain": 2, - "mix_gain": 11, - "rf_power": 16, - "dig_gain": 0 - }, - "tx_lut_11": { - "desc": "TX gain table, index 11", - "pa_gain": 3, - "mix_gain": 9, - "rf_power": 20, - "dig_gain": 0 - }, - "tx_lut_12": { - "desc": "TX gain table, index 12", - "pa_gain": 3, - "mix_gain": 11, - "rf_power": 23, - "dig_gain": 0 - }, - "tx_lut_13": { - "desc": "TX gain table, index 13", - "pa_gain": 3, - "mix_gain": 15, - "rf_power": 25, - "dig_gain": 0 - }, - "tx_lut_14": { - "desc": "TX gain table, index 14", - "pa_gain": 3, - "mix_gain": 15, - "rf_power": 26, - "dig_gain": 0 - }, - "tx_lut_15": { - "desc": "TX gain table, index 15", - "pa_gain": 3, - "mix_gain": 15, - "rf_power": 27, - "dig_gain": 0 - } - }, - "gateway_conf": { - "gateway_ID": "0000000000000000", - /* change with default server address/ports, or overwrite in local_conf.json */ - "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 enable */ - "gps_tty_path": "/dev/ttyAMA0", - "fake_gps": false, - "ref_latitude": 10, - "ref_longitude": 20, - "ref_altitude": -1, - "autoquit_threshold": 20, - "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 - } -} - diff --git a/lora/rak2245/global_conf/global_conf.eu_433.json b/lora/rak2245/global_conf/global_conf.eu_433.json deleted file mode 100755 index 240e7c1..0000000 --- a/lora/rak2245/global_conf/global_conf.eu_433.json +++ /dev/null @@ -1,230 +0,0 @@ -{ - - "SX1301_conf": { - "lorawan_public": true, - "clksrc": 1, /* radio_1 provides clock to concentrator */ - "antenna_gain": 0, /* antenna gain, in dBi */ - "radio_0": { - "enable": true, - "type": "SX1255", - "freq": 434375000, - "rssi_offset": -166.0, - "tx_enable": true, - "tx_freq_min": 433050000, - "tx_freq_max": 434900000 - }, - "radio_1": { - "enable": true, - "type": "SX1255", - "freq": 433575000, - "rssi_offset": -166.0, - "tx_enable": false - }, - "chan_multiSF_0": { - /* Lora MAC channel, 125kHz, all SF, 433.175 MHz */ - "enable": true, - "radio": 1, - "if": -400000 - }, - "chan_multiSF_1": { - /* Lora MAC channel, 125kHz, all SF, 433.375 MHz */ - "enable": true, - "radio": 1, - "if": -200000 - }, - "chan_multiSF_2": { - /* Lora MAC channel, 125kHz, all SF, 433.575 MHz */ - "enable": true, - "radio": 1, - "if": 0 - }, - "chan_multiSF_3": { - /* Lora MAC channel, 125kHz, all SF, 433.775 MHz */ - "enable": true, - "radio": 1, - "if": 200000 - }, - "chan_multiSF_4": { - /* Lora MAC channel, 125kHz, all SF, 433.975 MHz */ - "enable": true, - "radio": 0, - "if": -400000 - }, - "chan_multiSF_5": { - /* Lora MAC channel, 125kHz, all SF, 434.175 MHz */ - "enable": true, - "radio": 0, - "if": -200000 - }, - "chan_multiSF_6": { - /* Lora MAC channel, 125kHz, all SF, 434.375 MHz */ - "enable": true, - "radio": 0, - "if": 0 - }, - "chan_multiSF_7": { - /* Lora MAC channel, 125kHz, all SF, 434.575 MHz */ - "enable": true, - "radio": 0, - "if": 200000 - }, - "chan_Lora_std": { - /* Lora MAC channel, 250kHz, SF7, 434.175 MHz */ - "enable": true, - "radio": 1, - "if": -200000, - "bandwidth": 250000, - "spread_factor": 7 - }, - "chan_FSK": { - /* FSK 50kbps channel, 434.675 MHz */ - "enable": true, - "radio": 1, - "if": 300000, - "bandwidth": 125000, - "datarate": 50000 - }, - "tx_lut_0": { - /* TX gain table, index 0 */ - "pa_gain": 0, - "mix_gain": 8, - "rf_power": -6, - "dig_gain": 0 - }, - "tx_lut_1": { - /* TX gain table, index 1 */ - "pa_gain": 0, - "mix_gain": 10, - "rf_power": -3, - "dig_gain": 0 - }, - "tx_lut_2": { - /* TX gain table, index 2 */ - "pa_gain": 0, - "mix_gain": 12, - "rf_power": 0, - "dig_gain": 0 - }, - "tx_lut_3": { - /* TX gain table, index 3 */ - "pa_gain": 1, - "mix_gain": 8, - "rf_power": 3, - "dig_gain": 1 - }, - "tx_lut_4": { - /* TX gain table, index 4 */ - "pa_gain": 1, - "mix_gain": 9, - "rf_power": 6, - "dig_gain": 0 - }, - "tx_lut_5": { - /* TX gain table, index 5 */ - "pa_gain": 2, - "mix_gain": 8, - "rf_power": 10, - "dig_gain": 2 - }, - "tx_lut_6": { - /* TX gain table, index 6 */ - "pa_gain": 2, - "mix_gain": 8, - "rf_power": 11, - "dig_gain": 1 - }, - "tx_lut_7": { - /* TX gain table, index 7 */ - "pa_gain": 2, - "mix_gain": 8, - "rf_power": 12, - "dig_gain": 0 - }, - "tx_lut_8": { - /* TX gain table, index 8 */ - "pa_gain": 2, - "mix_gain": 9, - "rf_power": 13, - "dig_gain": 1 - }, - "tx_lut_9": { - /* TX gain table, index 9 */ - "pa_gain": 2, - "mix_gain": 9, - "rf_power": 14, - "dig_gain": 0 - }, - "tx_lut_10": { - /* TX gain table, index 10 */ - "pa_gain": 2, - "mix_gain": 10, - "rf_power": 16, - "dig_gain": 0 - }, - "tx_lut_11": { - /* TX gain table, index 11 */ - "pa_gain": 3, - "mix_gain": 8, - "rf_power": 20, - "dig_gain": 0 - }, - "tx_lut_12": { - "desc": "TX gain table, index 12", - "pa_gain": 3, - "mix_gain": 9, - "rf_power": 23, - "dig_gain": 0 - }, - "tx_lut_13": { - "desc": "TX gain table, index 13", - "pa_gain": 3, - "mix_gain": 10, - "rf_power": 25, - "dig_gain": 0 - }, - "tx_lut_14": { - "desc": "TX gain table, index 14", - "pa_gain": 3, - "mix_gain": 10, - "rf_power": 26, - "dig_gain": 0 - }, - "tx_lut_15": { - "desc": "TX gain table, index 15", - "pa_gain": 3, - "mix_gain": 10, - "rf_power": 27, - "dig_gain": 0 - } - }, - "gateway_conf": { - "gateway_ID": "0000000000000000", - /* change with default server address/ports, or overwrite in local_conf.json */ - "server_address": "router.eu.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 enable */ - "gps_tty_path": "/dev/ttyAMA0", - "fake_gps": false, - "ref_latitude": 10, - "ref_longitude": 20, - "ref_altitude": -1, - "autoquit_threshold": 20, - "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 - } -} - diff --git a/lora/rak2245/global_conf/global_conf.eu_863_870.json b/lora/rak2245/global_conf/global_conf.eu_863_870.json deleted file mode 100755 index 9666023..0000000 --- a/lora/rak2245/global_conf/global_conf.eu_863_870.json +++ /dev/null @@ -1,206 +0,0 @@ -{ - "SX1301_conf": { - "lorawan_public": true, - "clksrc": 1, - "antenna_gain": 0, - "radio_0": { - "enable": true, - "type": "SX1257", - "freq": 867500000, - "rssi_offset": -166.0, - "tx_enable": true, - "tx_freq_min": 863000000, - "tx_freq_max": 870000000 - }, - "radio_1": { - "enable": true, - "type": "SX1257", - "freq": 868500000, - "rssi_offset": -166.0, - "tx_enable": false - }, - "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": 0, - "if": -400000 - }, - "chan_multiSF_4": { - "enable": true, - "radio": 0, - "if": -200000 - }, - "chan_multiSF_5": { - "enable": true, - "radio": 0, - "if": 0 - }, - "chan_multiSF_6": { - "enable": true, - "radio": 0, - "if": 200000 - }, - "chan_multiSF_7": { - "enable": true, - "radio": 0, - "if": 400000 - }, - "chan_Lora_std": { - "enable": true, - "radio": 1, - "if": -200000, - "bandwidth": 250000, - "spread_factor": 7 - }, - "chan_FSK": { - "enable": true, - "radio": 1, - "if": 300000, - "bandwidth": 125000, - "datarate": 50000 - }, - "tx_lut_0": { - "pa_gain": 0, - "mix_gain": 9, - "rf_power": -6, - "dig_gain": 0 - }, - "tx_lut_1": { - "pa_gain": 0, - "mix_gain": 12, - "rf_power": -3, - "dig_gain": 0 - }, - "tx_lut_2": { - "pa_gain": 0, - "mix_gain": 15, - "rf_power": 0, - "dig_gain": 0 - }, - "tx_lut_3": { - "pa_gain": 1, - "mix_gain": 8, - "rf_power": 3, - "dig_gain": 1 - }, - "tx_lut_4": { - "pa_gain": 1, - "mix_gain": 9, - "rf_power": 6, - "dig_gain": 0 - }, - "tx_lut_5": { - "pa_gain": 1, - "mix_gain": 11, - "rf_power": 10, - "dig_gain": 0 - }, - "tx_lut_6": { - "pa_gain": 1, - "mix_gain": 12, - "rf_power": 11, - "dig_gain": 1 - }, - "tx_lut_7": { - "pa_gain": 1, - "mix_gain": 12, - "rf_power": 12, - "dig_gain": 0 - }, - "tx_lut_8": { - "pa_gain": 2, - "mix_gain": 11, - "rf_power": 13, - "dig_gain": 1 - }, - "tx_lut_9": { - "pa_gain": 2, - "mix_gain": 11, - "rf_power": 14, - "dig_gain": 0 - }, - "tx_lut_10": { - "pa_gain": 3, - "mix_gain": 8, - "rf_power": 16, - "dig_gain": 1 - }, - "tx_lut_11": { - "pa_gain": 3, - "mix_gain": 8, - "rf_power": 20, - "dig_gain": 0 - }, - "tx_lut_12": { - "desc": "TX gain table, index 12", - "pa_gain": 3, - "mix_gain": 12, - "rf_power": 23, - "dig_gain": 1 - }, - "tx_lut_13": { - "desc": "TX gain table, index 13", - "pa_gain": 3, - "mix_gain": 13, - "rf_power": 25, - "dig_gain": 0 - }, - "tx_lut_14": { - "desc": "TX gain table, index 14", - "pa_gain": 3, - "mix_gain": 13, - "rf_power": 26, - "dig_gain": 0 - }, - "tx_lut_15": { - "desc": "TX gain table, index 15", - "pa_gain": 3, - "mix_gain": 13, - "rf_power": 27, - "dig_gain": 0 - } - }, - "gateway_conf": { - "gateway_ID": "0000000000000000", - /* change with default server address/ports, or overwrite in local_conf.json */ - "server_address": "router.eu.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 enable */ - "gps_tty_path": "/dev/ttyAMA0", - "fake_gps": false, - "ref_latitude": 10, - "ref_longitude": 20, - "ref_altitude": -1, - "autoquit_threshold": 20, - "beacon_period": 0, /* disable class B beacon */ - "beacon_freq_hz": 869525000, - "beacon_freq_nb": 1, - "beacon_freq_step": 0, - "beacon_datarate": 9, - "beacon_bw_hz": 125000, - "beacon_power": 27 - } -} diff --git a/lora/rak2245/global_conf/global_conf.in_865_867.json b/lora/rak2245/global_conf/global_conf.in_865_867.json deleted file mode 100755 index 0149ab6..0000000 --- a/lora/rak2245/global_conf/global_conf.in_865_867.json +++ /dev/null @@ -1,203 +0,0 @@ -{ - "SX1301_conf": { - "lorawan_public": true, - "clksrc": 1, - "clksrc_desc": "radio_1 provides clock to concentrator for most devices except MultiTech. For MultiTech set to 0.", - "antenna_gain": 0, - "antenna_gain_desc": "antenna gain, in dBi", - "radio_0": { - "enable": true, - "type": "SX1257", - "freq": 865200000, - "rssi_offset": -166.0, - "tx_enable": true, - "tx_freq_min": 865000000, - "tx_freq_max": 867000000, - "tx_notch_freq": 129000 - }, - "radio_1": { - "enable": true, - "type": "SX1257", - "freq": 866385000, - "rssi_offset": -166.0, - "tx_enable": false - }, - "chan_multiSF_0": { - "desc": "Lora MAC, 125kHz, all SF, 865.0625 MHz", - "enable": true, - "radio": 0, - "if": -137500 - }, - "chan_multiSF_1": { - "desc": "Lora MAC, 125kHz, all SF, 865.4025 MHz", - "enable": true, - "radio": 0, - "if": 202500 - }, - "chan_multiSF_2": { - "desc": "Lora MAC, 125kHz, all SF, 865.9850 MHz", - "enable": true, - "radio": 1, - "if": -400000 - }, - "chan_multiSF_3": { - "desc": "disabled", - "enable": false - }, - "chan_multiSF_4": { - "desc": "disabled", - "enable": false - }, - "chan_multiSF_5": { - "desc": "disabled", - "enable": false - }, - "chan_multiSF_6": { - "desc": "disabled", - "enable": false - }, - "chan_multiSF_7": { - "desc": "disabled", - "enable": false - }, - "chan_Lora_std": { - "desc": "disabled", - "enable": false - }, - "chan_FSK": { - "desc": "disabled", - "enable": false - }, - "tx_lut_0": { - "pa_gain": 0, - "mix_gain": 9, - "rf_power": -6, - "dig_gain": 0 - }, - "tx_lut_1": { - "pa_gain": 0, - "mix_gain": 12, - "rf_power": -3, - "dig_gain": 0 - }, - "tx_lut_2": { - "pa_gain": 0, - "mix_gain": 15, - "rf_power": 0, - "dig_gain": 0 - }, - "tx_lut_3": { - "pa_gain": 1, - "mix_gain": 8, - "rf_power": 3, - "dig_gain": 1 - }, - "tx_lut_4": { - "pa_gain": 1, - "mix_gain": 9, - "rf_power": 6, - "dig_gain": 0 - }, - "tx_lut_5": { - "pa_gain": 1, - "mix_gain": 11, - "rf_power": 10, - "dig_gain": 0 - }, - "tx_lut_6": { - "pa_gain": 1, - "mix_gain": 12, - "rf_power": 11, - "dig_gain": 1 - }, - "tx_lut_7": { - "pa_gain": 1, - "mix_gain": 12, - "rf_power": 12, - "dig_gain": 0 - }, - "tx_lut_8": { - "pa_gain": 2, - "mix_gain": 11, - "rf_power": 13, - "dig_gain": 1 - }, - "tx_lut_9": { - "pa_gain": 2, - "mix_gain": 11, - "rf_power": 14, - "dig_gain": 0 - }, - "tx_lut_10": { - "pa_gain": 3, - "mix_gain": 8, - "rf_power": 16, - "dig_gain": 1 - }, - "tx_lut_11": { - "pa_gain": 3, - "mix_gain": 8, - "rf_power": 20, - "dig_gain": 0 - }, - "tx_lut_12": { - "desc": "TX gain table, index 12", - "pa_gain": 3, - "mix_gain": 12, - "rf_power": 23, - "dig_gain": 1 - }, - "tx_lut_13": { - "desc": "TX gain table, index 13", - "pa_gain": 3, - "mix_gain": 13, - "rf_power": 25, - "dig_gain": 0 - }, - "tx_lut_14": { - "desc": "TX gain table, index 14", - "pa_gain": 3, - "mix_gain": 13, - "rf_power": 26, - "dig_gain": 0 - }, - "tx_lut_15": { - "desc": "TX gain table, index 15", - "pa_gain": 3, - "mix_gain": 13, - "rf_power": 27, - "dig_gain": 0 - } - }, - "gateway_conf": { - "gateway_ID": "0000000000000000", - /* change with default server address/ports, or overwrite in local_conf.json */ - "server_address": "router.as.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 enable */ - "gps_tty_path": "/dev/ttyAMA0", - "fake_gps": false, - "ref_latitude": 10, - "ref_longitude": 20, - "ref_altitude": -1, - "autoquit_threshold": 20, - "beacon_period": 0, /* disable class B beacon */ - "beacon_freq_hz": 866500000, - "beacon_freq_nb": 1, - "beacon_freq_step": 0, - "beacon_datarate": 8, - "beacon_bw_hz": 125000, - "beacon_power": 27 - } - -} - diff --git a/lora/rak2245/global_conf/global_conf.kr_920_923.json b/lora/rak2245/global_conf/global_conf.kr_920_923.json deleted file mode 100755 index c0ab8cf..0000000 --- a/lora/rak2245/global_conf/global_conf.kr_920_923.json +++ /dev/null @@ -1,223 +0,0 @@ -{ - "SX1301_conf": { - "lorawan_public": true, - "clksrc": 1, - "clksrc_desc": "radio_1 provides clock to concentrator for most devices except MultiTech. For MultiTech set to 0.", - "antenna_gain": 0, - "antenna_gain_desc": "antenna gain, in dBi", - "radio_0": { - "enable": true, - "type": "SX1257", - "freq": 922400000, - "rssi_offset": -166.0, - "tx_enable": true, - "tx_freq_min": 920900000, - "tx_freq_max": 923300000 - }, - "radio_1": { - "enable": true, - "type": "SX1257", - "freq": 923000000, - "rssi_offset": -166.0, - "tx_enable": false - }, - "chan_multiSF_0": { - "desc": "Lora MAC, 125kHz, all SF, 922.1 MHz", - "enable": true, - "radio": 0, - "if": -300000 - }, - "chan_multiSF_1": { - "desc": "Lora MAC, 125kHz, all SF, 922.3 MHz", - "enable": true, - "radio": 0, - "if": -100000 - }, - "chan_multiSF_2": { - "desc": "Lora MAC, 125kHz, all SF, 922.5 MHz", - "enable": true, - "radio": 0, - "if": 100000 - }, - "chan_multiSF_3": { - "desc": "Lora MAC, 125kHz, all SF, 922.7 MHz", - "enable": true, - "radio": 0, - "if": 300000 - }, - "chan_multiSF_4": { - "desc": "Lora MAC, 125kHz, all SF, 922.9 MHz", - "enable": true, - "radio": 1, - "if": -100000 - }, - "chan_multiSF_5": { - "desc": "Lora MAC, 125kHz, all SF, 923.1 MHz", - "enable": true, - "radio": 1, - "if": 100000 - }, - "chan_multiSF_6": { - "desc": "Lora MAC, 125kHz, all SF, 923.3 MHz", - "enable": true, - "radio": 1, - "if": 300000 - }, - "chan_multiSF_7": { - "desc": "disabled", - "enable": false - }, - "chan_Lora_std": { - "desc": "disabled", - "enable": false - }, - "chan_FSK": { - "desc": "disabled", - "enable": false - }, - "tx_lut_0": { - "desc": "TX gain table, index 0", - "pa_gain": 0, - "mix_gain": 9, - "rf_power": -6, - "dig_gain": 0 - }, - "tx_lut_1": { - "desc": "TX gain table, index 1", - "pa_gain": 0, - "mix_gain": 11, - "rf_power": -3, - "dig_gain": 0 - }, - "tx_lut_2": { - "desc": "TX gain table, index 2", - "pa_gain": 0, - "mix_gain": 15, - "rf_power": 0, - "dig_gain": 0 - }, - "tx_lut_3": { - "desc": "TX gain table, index 3", - "pa_gain": 1, - "mix_gain": 8, - "rf_power": 3, - "dig_gain": 0 - }, - "tx_lut_4": { - "desc": "TX gain table, index 4", - "pa_gain": 1, - "mix_gain": 10, - "rf_power": 6, - "dig_gain": 0 - }, - "tx_lut_5": { - "desc": "TX gain table, index 5", - "pa_gain": 1, - "mix_gain": 13, - "rf_power": 10, - "dig_gain": 1 - }, - "tx_lut_6": { - "desc": "TX gain table, index 6", - "pa_gain": 1, - "mix_gain": 14, - "rf_power": 11, - "dig_gain": 0 - }, - "tx_lut_7": { - "desc": "TX gain table, index 7", - "pa_gain": 2, - "mix_gain": 10, - "rf_power": 12, - "dig_gain": 0 - }, - "tx_lut_8": { - "desc": "TX gain table, index 8", - "pa_gain": 2, - "mix_gain": 10, - "rf_power": 13, - "dig_gain": 0 - }, - "tx_lut_9": { - "desc": "TX gain table, index 9", - "pa_gain": 2, - "mix_gain": 11, - "rf_power": 14, - "dig_gain": 1 - }, - "tx_lut_10": { - "desc": "TX gain table, index 10", - "pa_gain": 2, - "mix_gain": 12, - "rf_power": 16, - "dig_gain": 0 - }, - "tx_lut_11": { - "desc": "TX gain table, index 11", - "pa_gain": 3, - "mix_gain": 9, - "rf_power": 20, - "dig_gain": 1 - }, - "tx_lut_12": { - "desc": "TX gain table, index 12", - "pa_gain": 3, - "mix_gain": 11, - "rf_power": 23, - "dig_gain": 1 - }, - "tx_lut_13": { - "desc": "TX gain table, index 13", - "pa_gain": 3, - "mix_gain": 12, - "rf_power": 25, - "dig_gain": 1 - }, - "tx_lut_14": { - "desc": "TX gain table, index 14", - "pa_gain": 3, - "mix_gain": 13, - "rf_power": 26, - "dig_gain": 1 - }, - "tx_lut_15": { - "desc": "TX gain table, index 15", - "pa_gain": 3, - "mix_gain": 13, - "rf_power": 27, - "dig_gain": 0 - } - }, - "gateway_conf": { - "gateway_ID": "0000000000000000", - /* change with default server address/ports, or overwrite in local_conf.json */ - "server_address": "router.kr.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 enable */ - "gps_tty_path": "/dev/ttyAMA0", - "fake_gps": false, - "ref_latitude": 10, - "ref_longitude": 20, - "ref_altitude": -1, - "autoquit_threshold": 20, - "beacon_period": 0, /* disable class B beacon */ - "beacon_freq_hz": 923100000, - "beacon_freq_nb": 1, - "beacon_freq_step": 0, - "beacon_datarate": 9, - "beacon_bw_hz": 125000, - "beacon_power": 27 - } - -} - - diff --git a/lora/rak2245/global_conf/global_conf.ru_864_870.json b/lora/rak2245/global_conf/global_conf.ru_864_870.json deleted file mode 100755 index e9b90a5..0000000 --- a/lora/rak2245/global_conf/global_conf.ru_864_870.json +++ /dev/null @@ -1,210 +0,0 @@ -{ - "SX1301_conf": { - "lorawan_public": true, - "clksrc": 1, - "clksrc_desc": "radio_1 provides clock to concentrator for most devices except MultiTech. For MultiTech set to 0.", - "antenna_gain": 0, - "antenna_gain_desc": "antenna gain, in dBi", - "radio_0": { - "enable": true, - "type": "SX1257", - "freq": 864500000, - "rssi_offset": -166.0, - "tx_enable": true, - "tx_freq_min": 863000000, - "tx_freq_max": 870000000 - }, - "radio_1": { - "enable": true, - "type": "SX1257", - "freq": 869000000, - "rssi_offset": -166.0, - "tx_enable": false - }, - "chan_multiSF_0": { - "desc": "Lora MAC, 125kHz, all SF, 864.1 MHz", - "enable": true, - "radio": 0, - "if": -400000 - }, - "chan_multiSF_1": { - "desc": "Lora MAC, 125kHz, all SF, 864.3 MHz", - "enable": true, - "radio": 0, - "if": -200000 - }, - "chan_multiSF_2": { - "desc": "Lora MAC, 125kHz, all SF, 864.5 MHz", - "enable": true, - "radio": 0, - "if": 0 - }, - "chan_multiSF_3": { - "desc": "Lora MAC, 125kHz, all SF, 864.7 MHz", - "enable": true, - "radio": 0, - "if": 200000 - }, - "chan_multiSF_4": { - "desc": "Lora MAC, 125kHz, all SF, 864.9 MHz", - "enable": true, - "radio": 0, - "if": 400000 - }, - "chan_multiSF_5": { - "desc": "Lora MAC, 125kHz, all SF, 868.9 MHz", - "enable": true, - "radio": 1, - "if": -100000 - }, - "chan_multiSF_6": { - "desc": "Lora MAC, 125kHz, all SF, 869.1 MHz", - "enable": true, - "radio": 1, - "if": 100000 - }, - "chan_multiSF_7": { - "desc": "disabled", - "enable": false - }, - "chan_Lora_std": { - "desc": "disabled", - "enable": false - }, - "chan_FSK": { - "desc": "disabled", - "enable": false - }, - "tx_lut_0": { - "pa_gain": 0, - "mix_gain": 9, - "rf_power": -6, - "dig_gain": 0 - }, - "tx_lut_1": { - "pa_gain": 0, - "mix_gain": 12, - "rf_power": -3, - "dig_gain": 0 - }, - "tx_lut_2": { - "pa_gain": 0, - "mix_gain": 15, - "rf_power": 0, - "dig_gain": 0 - }, - "tx_lut_3": { - "pa_gain": 1, - "mix_gain": 8, - "rf_power": 3, - "dig_gain": 1 - }, - "tx_lut_4": { - "pa_gain": 1, - "mix_gain": 9, - "rf_power": 6, - "dig_gain": 0 - }, - "tx_lut_5": { - "pa_gain": 1, - "mix_gain": 11, - "rf_power": 10, - "dig_gain": 0 - }, - "tx_lut_6": { - "pa_gain": 1, - "mix_gain": 12, - "rf_power": 11, - "dig_gain": 1 - }, - "tx_lut_7": { - "pa_gain": 1, - "mix_gain": 12, - "rf_power": 12, - "dig_gain": 0 - }, - "tx_lut_8": { - "pa_gain": 2, - "mix_gain": 11, - "rf_power": 13, - "dig_gain": 1 - }, - "tx_lut_9": { - "pa_gain": 2, - "mix_gain": 11, - "rf_power": 14, - "dig_gain": 0 - }, - "tx_lut_10": { - "pa_gain": 3, - "mix_gain": 8, - "rf_power": 16, - "dig_gain": 1 - }, - "tx_lut_11": { - "pa_gain": 3, - "mix_gain": 8, - "rf_power": 20, - "dig_gain": 0 - }, - "tx_lut_12": { - "desc": "TX gain table, index 12", - "pa_gain": 3, - "mix_gain": 12, - "rf_power": 23, - "dig_gain": 1 - }, - "tx_lut_13": { - "desc": "TX gain table, index 13", - "pa_gain": 3, - "mix_gain": 13, - "rf_power": 25, - "dig_gain": 0 - }, - "tx_lut_14": { - "desc": "TX gain table, index 14", - "pa_gain": 3, - "mix_gain": 13, - "rf_power": 26, - "dig_gain": 0 - }, - "tx_lut_15": { - "desc": "TX gain table, index 15", - "pa_gain": 3, - "mix_gain": 13, - "rf_power": 27, - "dig_gain": 0 - } - }, - "gateway_conf": { - "gateway_ID": "0000000000000000", - /* change with default server address/ports, or overwrite in local_conf.json */ - "server_address": "router.ru.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 enable */ - "gps_tty_path": "/dev/ttyAMA0", - "fake_gps": false, - "ref_latitude": 10, - "ref_longitude": 20, - "ref_altitude": -1, - "autoquit_threshold": 20, - "beacon_period": 0, /* disable class B beacon */ - "beacon_freq_hz": 869100000, - "beacon_freq_nb": 1, - "beacon_freq_step": 0, - "beacon_datarate": 9, - "beacon_bw_hz": 125000, - "beacon_power": 27 - } - -} - diff --git a/lora/rak2245/global_conf/global_conf.us_902_928.json b/lora/rak2245/global_conf/global_conf.us_902_928.json deleted file mode 100755 index c8e0993..0000000 --- a/lora/rak2245/global_conf/global_conf.us_902_928.json +++ /dev/null @@ -1,218 +0,0 @@ -{ - "SX1301_conf": { - "lorawan_public": true, - "clksrc": 1, - "antenna_gain": 0, - "radio_0": { - "enable": true, - "type": "SX1257", - "freq": 904300000, - "rssi_offset": -166.0, - "tx_enable": true, - "tx_freq_min": 902000000, - "tx_freq_max": 928000000 - }, - "radio_1": { - "enable": true, - "type": "SX1257", - "freq": 905000000, - "rssi_offset": -166.0, - "tx_enable": false - }, - "chan_multiSF_0": { - "enable": true, - "radio": 0, - "if": -400000 - }, - "chan_multiSF_1": { - "enable": true, - "radio": 0, - "if": -200000 - }, - "chan_multiSF_2": { - "enable": true, - "radio": 0, - "if": 0 - }, - "chan_multiSF_3": { - "enable": true, - "radio": 0, - "if": 200000 - }, - "chan_multiSF_4": { - "enable": true, - "radio": 1, - "if": -300000 - }, - "chan_multiSF_5": { - "enable": true, - "radio": 1, - "if": -100000 - }, - "chan_multiSF_6": { - "enable": true, - "radio": 1, - "if": 100000 - }, - "chan_multiSF_7": { - "enable": true, - "radio": 1, - "if": 300000 - }, - "chan_Lora_std": { - "enable": true, - "radio": 0, - "if": 300000, - "bandwidth": 500000, - "spread_factor": 8 - }, - "chan_FSK": { - "enable": false, - "radio": 0, - "if": 300000, - "bandwidth": 250000, - "datarate": 100000 - }, - "tx_lut_0": { - "desc": "TX gain table, index 0", - "pa_gain": 0, - "mix_gain": 9, - "rf_power": -6, - "dig_gain": 0 - }, - "tx_lut_1": { - "desc": "TX gain table, index 1", - "pa_gain": 0, - "mix_gain": 11, - "rf_power": -3, - "dig_gain": 0 - }, - "tx_lut_2": { - "desc": "TX gain table, index 2", - "pa_gain": 0, - "mix_gain": 15, - "rf_power": 0, - "dig_gain": 0 - }, - "tx_lut_3": { - "desc": "TX gain table, index 3", - "pa_gain": 1, - "mix_gain": 8, - "rf_power": 3, - "dig_gain": 0 - }, - "tx_lut_4": { - "desc": "TX gain table, index 4", - "pa_gain": 1, - "mix_gain": 10, - "rf_power": 6, - "dig_gain": 0 - }, - "tx_lut_5": { - "desc": "TX gain table, index 5", - "pa_gain": 1, - "mix_gain": 13, - "rf_power": 10, - "dig_gain": 1 - }, - "tx_lut_6": { - "desc": "TX gain table, index 6", - "pa_gain": 1, - "mix_gain": 14, - "rf_power": 11, - "dig_gain": 0 - }, - "tx_lut_7": { - "desc": "TX gain table, index 7", - "pa_gain": 2, - "mix_gain": 10, - "rf_power": 12, - "dig_gain": 0 - }, - "tx_lut_8": { - "desc": "TX gain table, index 8", - "pa_gain": 2, - "mix_gain": 10, - "rf_power": 13, - "dig_gain": 0 - }, - "tx_lut_9": { - "desc": "TX gain table, index 9", - "pa_gain": 2, - "mix_gain": 11, - "rf_power": 14, - "dig_gain": 1 - }, - "tx_lut_10": { - "desc": "TX gain table, index 10", - "pa_gain": 2, - "mix_gain": 12, - "rf_power": 16, - "dig_gain": 0 - }, - "tx_lut_11": { - "desc": "TX gain table, index 11", - "pa_gain": 3, - "mix_gain": 9, - "rf_power": 20, - "dig_gain": 1 - }, - "tx_lut_12": { - "desc": "TX gain table, index 12", - "pa_gain": 3, - "mix_gain": 11, - "rf_power": 23, - "dig_gain": 1 - }, - "tx_lut_13": { - "desc": "TX gain table, index 13", - "pa_gain": 3, - "mix_gain": 12, - "rf_power": 25, - "dig_gain": 1 - }, - "tx_lut_14": { - "desc": "TX gain table, index 14", - "pa_gain": 3, - "mix_gain": 13, - "rf_power": 26, - "dig_gain": 1 - }, - "tx_lut_15": { - "desc": "TX gain table, index 15", - "pa_gain": 3, - "mix_gain": 13, - "rf_power": 27, - "dig_gain": 0 - } - }, - "gateway_conf": { - "gateway_ID": "0000000000000000", - /* change with default server address/ports, or overwrite in local_conf.json */ - "server_address": "router.us.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 enable */ - "gps_tty_path": "/dev/ttyAMA0", - "fake_gps": false, - "ref_latitude": 10, - "ref_longitude": 20, - "ref_altitude": -1, - "autoquit_threshold": 20, - "beacon_period": 0, /* disable class B beacon */ - "beacon_freq_hz": 923300000, - "beacon_freq_nb": 8, - "beacon_freq_step": 600000, - "beacon_datarate": 12, - "beacon_bw_hz": 500000, - "beacon_power": 27 - } -} diff --git a/lora/rak2245/install.sh b/lora/rak2245/install.sh deleted file mode 100755 index bb896d6..0000000 --- a/lora/rak2245/install.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/bash - -# Stop on the first sign of trouble -set -e - -if [ $UID != 0 ]; then - echo "ERROR: Operation not permitted. Forgot sudo?" - exit 1 -fi - -SCRIPT_DIR=$(pwd) - -# Request gateway configuration data -# There are two ways to do it, manually specify everything -# or rely on the gateway EUI and retrieve settings files from remote (recommended) -echo "Gateway configuration:" - -# Install LoRaWAN packet forwarder repositories -INSTALL_DIR="./" -if [ ! -d "$INSTALL_DIR" ]; then mkdir $INSTALL_DIR; fi -pushd $INSTALL_DIR - -# Build LoRa gateway app - -if [ ! -d $SCRIPT_DIR/../lora_gateway ]; then - git clone https://github.com/Lora-net/lora_gateway.git -else - cp $SCRIPT_DIR/../lora_gateway . -rf -fi - -pushd lora_gateway - -cp $SCRIPT_DIR/library.cfg ./libloragw/library.cfg -cp $SCRIPT_DIR/loragw_spi.native.c ./libloragw/src/loragw_spi.native.c -cp $SCRIPT_DIR/../print_lora_log.sh util_pkt_logger/ -make - -popd - -# Build packet forwarder - -if [ ! -d $SCRIPT_DIR/../packet_forwarder ]; then - git clone https://github.com/Lora-net/packet_forwarder.git -else - cp $SCRIPT_DIR/../packet_forwarder . -rf -fi - -pushd packet_forwarder - -cp $SCRIPT_DIR/lora_pkt_fwd.c ./lora_pkt_fwd/src/lora_pkt_fwd.c - -make -rm lora_pkt_fwd/obj/* -f -popd - -cp global_conf $INSTALL_DIR/packet_forwarder/lora_pkt_fwd/ -rf -cp global_conf/global_conf.eu_863_870.json $INSTALL_DIR/packet_forwarder/lora_pkt_fwd/global_conf.json -sed -i "s/^.*server_address.*$/\t\"server_address\": \"127.0.0.1\",/" $INSTALL_DIR/packet_forwarder/lora_pkt_fwd/global_conf.json -rm -f $INSTALL_DIR/packet_forwarder/lora_pkt_fwd/local_conf.json - diff --git a/lora/rak2245/library.cfg b/lora/rak2245/library.cfg deleted file mode 100644 index 9455ee6..0000000 --- a/lora/rak2245/library.cfg +++ /dev/null @@ -1,18 +0,0 @@ -# That file will be included in the Makefile files that have hardware dependencies - -### Debug options ### -# Set the DEBUG_* to 1 to activate debug mode in individual modules. -# Warning: that makes the module *very verbose*, do not use for production - -CFG_SPI= native - -PLATFORM= imst_rpi - -#CFG_BAND= au915 - -DEBUG_AUX= 0 -DEBUG_SPI= 0 -DEBUG_REG= 0 -DEBUG_HAL= 0 -DEBUG_LBT= 0 -DEBUG_GPS= 0 diff --git a/lora/rak2245/lora_pkt_fwd.c b/lora/rak2245/lora_pkt_fwd.c deleted file mode 100644 index 1cdf15b..0000000 --- a/lora/rak2245/lora_pkt_fwd.c +++ /dev/null @@ -1,2959 +0,0 @@ -/* - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ - \____ \| ___ | (_ _) ___ |/ ___) _ \ - _____) ) ____| | | || |_| ____( (___| | | | -(______/|_____)_|_|_| \__)_____)\____)_| |_| - (C)2013 Semtech-Cycleo - -Description: - Configure Lora concentrator and forward packets to a server - Use GPS for packet timestamping. - Send a becon at a regular interval without server intervention - -License: Revised BSD License, see LICENSE.TXT file include in the project -Maintainer: Michael Coracin -*/ - - -/* -------------------------------------------------------------------------- */ -/* --- 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, snprintf, fopen, fputs */ - -#include /* memset */ -#include /* sigaction */ -#include /* time, clock_gettime, strftime, gmtime */ -#include /* timeval */ -#include /* getopt, access */ -#include /* atoi, exit */ -#include /* error messages */ -#include /* modf */ -#include - -#include /* socket specific definitions */ -#include /* INET constants and stuff */ -#include /* IP address conversion stuff */ -#include /* gai_strerror */ - -#include - -#include "trace.h" -#include "jitqueue.h" -#include "timersync.h" -#include "parson.h" -#include "base64.h" -#include "loragw_hal.h" -#include "loragw_gps.h" -#include "loragw_aux.h" -#include "loragw_reg.h" - -/* -------------------------------------------------------------------------- */ -/* --- PRIVATE MACROS ------------------------------------------------------- */ - -#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -#define STRINGIFY(x) #x -#define STR(x) STRINGIFY(x) - -/* -------------------------------------------------------------------------- */ -/* --- PRIVATE CONSTANTS ---------------------------------------------------- */ - -#ifndef VERSION_STRING - #define VERSION_STRING "undefined" -#endif - -#define DEFAULT_SERVER 127.0.0.1 /* hostname also supported */ -#define DEFAULT_PORT_UP 1780 -#define DEFAULT_PORT_DW 1782 -#define DEFAULT_KEEPALIVE 5 /* default time interval for downstream keep-alive packet */ -#define DEFAULT_STAT 30 /* default time interval for statistics */ -#define PUSH_TIMEOUT_MS 100 -#define PULL_TIMEOUT_MS 200 -#define GPS_REF_MAX_AGE 30 /* maximum admitted delay in seconds of GPS loss before considering latest GPS sync unusable */ -#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 XERR_INIT_AVG 128 /* 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 -#define PKT_PUSH_ACK 1 -#define PKT_PULL_DATA 2 -#define PKT_PULL_RESP 3 -#define PKT_PULL_ACK 4 -#define PKT_TX_ACK 5 - -#define NB_PKT_MAX 8 /* max number of packets per fetch/send cycle */ - -#define MIN_LORA_PREAMB 6 /* minimum Lora preamble length for this application */ -#define STD_LORA_PREAMB 8 -#define MIN_FSK_PREAMB 3 /* minimum FSK preamble length for this application */ -#define STD_FSK_PREAMB 5 - -#define STATUS_SIZE 200 -#define TX_BUFF_SIZE ((540 * NB_PKT_MAX) + 30 + STATUS_SIZE) - -#define UNIX_GPS_EPOCH_OFFSET 315964800 /* Number of seconds ellapsed between 01.Jan.1970 00:00:00 - and 06.Jan.1980 00:00:00 */ - -#define DEFAULT_BEACON_FREQ_HZ 869525000 -#define DEFAULT_BEACON_FREQ_NB 1 -#define DEFAULT_BEACON_FREQ_STEP 0 -#define DEFAULT_BEACON_DATARATE 9 -#define DEFAULT_BEACON_BW_HZ 125000 -#define DEFAULT_BEACON_POWER 14 -#define DEFAULT_BEACON_INFODESC 0 - -/* -------------------------------------------------------------------------- */ -/* --- PRIVATE VARIABLES (GLOBAL) ------------------------------------------- */ - -/* signal handling variables */ -volatile bool exit_sig = false; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */ -volatile bool quit_sig = false; /* 1 -> application terminates without shutting down the hardware */ - -/* packets filtering configuration variables */ -static bool fwd_valid_pkt = true; /* packets with PAYLOAD CRC OK are forwarded */ -static bool fwd_error_pkt = false; /* packets with PAYLOAD CRC ERROR are NOT forwarded */ -static bool fwd_nocrc_pkt = false; /* packets with NO PAYLOAD CRC are NOT forwarded */ - -/* network configuration variables */ -static uint64_t lgwm = 0; /* Lora gateway MAC address */ -static char serv_addr[64] = STR(DEFAULT_SERVER); /* address of the server (host name or IPv4/IPv6) */ -static char serv_port_up[8] = STR(DEFAULT_PORT_UP); /* server port for upstream traffic */ -static char serv_port_down[8] = STR(DEFAULT_PORT_DW); /* server port for downstream traffic */ -static int keepalive_time = DEFAULT_KEEPALIVE; /* send a PULL_DATA request every X seconds, negative = disabled */ - -/* statistics collection configuration variables */ -static unsigned stat_interval = DEFAULT_STAT; /* time interval (in sec) at which statistics are collected and displayed */ - -/* gateway <-> MAC protocol variables */ -static uint32_t net_mac_h; /* Most Significant Nibble, network order */ -static uint32_t net_mac_l; /* Least Significant Nibble, network order */ - -/* network sockets */ -static int sock_up; /* socket for upstream traffic */ -static int sock_down; /* socket for downstream traffic */ - -/* network protocol variables */ -static struct timeval push_timeout_half = {0, (PUSH_TIMEOUT_MS * 500)}; /* cut in half, critical for throughput */ -static struct timeval pull_timeout = {0, (PULL_TIMEOUT_MS * 1000)}; /* non critical for throughput */ - -/* hardware access control and correction */ -pthread_mutex_t mx_concent = PTHREAD_MUTEX_INITIALIZER; /* control access to the concentrator */ -static pthread_mutex_t mx_xcorr = PTHREAD_MUTEX_INITIALIZER; /* control access to the XTAL correction */ -static bool xtal_correct_ok = false; /* set true when XTAL correction is stable enough */ -static double xtal_correct = 1.0; - -/* GPS configuration and synchronization */ -static char gps_tty_path[64] = "\0"; /* path of the TTY port GPS is connected on */ -static int gps_tty_fd = -1; /* file descriptor of the GPS TTY port */ -static bool gps_enabled = false; /* is GPS enabled on that gateway ? */ - -/* GPS time reference */ -static pthread_mutex_t mx_timeref = PTHREAD_MUTEX_INITIALIZER; /* control access to GPS time reference */ -static bool gps_ref_valid; /* is GPS reference acceptable (ie. not too old) */ -static struct tref time_reference_gps; /* time reference used for GPS <-> timestamp conversion */ - -/* Reference coordinates, for broadcasting (beacon) */ -static struct coord_s reference_coord; - -/* Enable faking the GPS coordinates of the gateway */ -static bool gps_fake_enable; /* enable the feature */ - -/* measurements to establish statistics */ -static pthread_mutex_t mx_meas_up = PTHREAD_MUTEX_INITIALIZER; /* control access to the upstream measurements */ -static uint32_t meas_nb_rx_rcv = 0; /* count packets received */ -static uint32_t meas_nb_rx_ok = 0; /* count packets received with PAYLOAD CRC OK */ -static uint32_t meas_nb_rx_bad = 0; /* count packets received with PAYLOAD CRC ERROR */ -static uint32_t meas_nb_rx_nocrc = 0; /* count packets received with NO PAYLOAD CRC */ -static uint32_t meas_up_pkt_fwd = 0; /* number of radio packet forwarded to the server */ -static uint32_t meas_up_network_byte = 0; /* sum of UDP bytes sent for upstream traffic */ -static uint32_t meas_up_payload_byte = 0; /* sum of radio payload bytes sent for upstream traffic */ -static uint32_t meas_up_dgram_sent = 0; /* number of datagrams sent for upstream traffic */ -static uint32_t meas_up_ack_rcv = 0; /* number of datagrams acknowledged for upstream traffic */ - -static pthread_mutex_t mx_meas_dw = PTHREAD_MUTEX_INITIALIZER; /* control access to the downstream measurements */ -static uint32_t meas_dw_pull_sent = 0; /* number of PULL requests sent for downstream traffic */ -static uint32_t meas_dw_ack_rcv = 0; /* number of PULL requests acknowledged for downstream traffic */ -static uint32_t meas_dw_dgram_rcv = 0; /* count PULL response packets received for downstream traffic */ -static uint32_t meas_dw_network_byte = 0; /* sum of UDP bytes sent for upstream traffic */ -static uint32_t meas_dw_payload_byte = 0; /* sum of radio payload bytes sent for upstream traffic */ -static uint32_t meas_nb_tx_ok = 0; /* count packets emitted successfully */ -static uint32_t meas_nb_tx_fail = 0; /* count packets were TX failed for other reasons */ -static uint32_t meas_nb_tx_requested = 0; /* count TX request from server (downlinks) */ -static uint32_t meas_nb_tx_rejected_collision_packet = 0; /* count packets were TX request were rejected due to collision with another packet already programmed */ -static uint32_t meas_nb_tx_rejected_collision_beacon = 0; /* count packets were TX request were rejected due to collision with a beacon already programmed */ -static uint32_t meas_nb_tx_rejected_too_late = 0; /* count packets were TX request were rejected because it is too late to program it */ -static uint32_t meas_nb_tx_rejected_too_early = 0; /* count packets were TX request were rejected because timestamp is too much in advance */ -static uint32_t meas_nb_beacon_queued = 0; /* count beacon inserted in jit queue */ -static uint32_t meas_nb_beacon_sent = 0; /* count beacon actually sent to concentrator */ -static uint32_t meas_nb_beacon_rejected = 0; /* count beacon rejected for queuing */ - -static pthread_mutex_t mx_meas_gps = PTHREAD_MUTEX_INITIALIZER; /* control access to the GPS statistics */ -static bool gps_coord_valid; /* could we get valid GPS coordinates ? */ -static struct coord_s meas_gps_coord; /* GPS position of the gateway */ -static struct coord_s meas_gps_err; /* GPS position of the gateway */ - -static pthread_mutex_t mx_stat_rep = PTHREAD_MUTEX_INITIALIZER; /* control access to the status report */ -static bool report_ready = false; /* true when there is a new report to send to the server */ -static char status_report[STATUS_SIZE]; /* status report as a JSON object */ - -/* beacon parameters */ -static uint32_t beacon_period = 0; /* set beaconing period, must be a sub-multiple of 86400, the nb of sec in a day */ -static uint32_t beacon_freq_hz = DEFAULT_BEACON_FREQ_HZ; /* set beacon TX frequency, in Hz */ -static uint8_t beacon_freq_nb = DEFAULT_BEACON_FREQ_NB; /* set number of beaconing channels beacon */ -static uint32_t beacon_freq_step = DEFAULT_BEACON_FREQ_STEP; /* set frequency step between beacon channels, in Hz */ -static uint8_t beacon_datarate = DEFAULT_BEACON_DATARATE; /* set beacon datarate (SF) */ -static uint32_t beacon_bw_hz = DEFAULT_BEACON_BW_HZ; /* set beacon bandwidth, in Hz */ -static int8_t beacon_power = DEFAULT_BEACON_POWER; /* set beacon TX power, in dBm */ -static uint8_t beacon_infodesc = DEFAULT_BEACON_INFODESC; /* set beacon information descriptor */ - -/* auto-quit function */ -static uint32_t autoquit_threshold = 0; /* enable auto-quit after a number of non-acknowledged PULL_DATA (0 = disabled)*/ - -/* Just In Time TX scheduling */ -static struct jit_queue_s jit_queue; - -/* Gateway specificities */ -static int8_t antenna_gain = 0; - -/* TX capabilities */ -static struct lgw_tx_gain_lut_s txlut; /* 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 */ - -/* -------------------------------------------------------------------------- */ -/* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */ - -static void sig_handler(int sigio); - -static int parse_SX1301_configuration(const char * conf_file); - -static int parse_gateway_configuration(const char * conf_file); - -static uint16_t crc16(const uint8_t * data, unsigned size); - -static double difftimespec(struct timespec end, struct timespec beginning); - -static void gps_process_sync(void); - -static void gps_process_coords(void); - -/* threads */ -void thread_up(void); -void thread_down(void); -void thread_gps(void); -void thread_valid(void); -void thread_jit(void); -void thread_timersync(void); - -/* -------------------------------------------------------------------------- */ -/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */ - -static void sig_handler(int sigio) { - if (sigio == SIGQUIT) { - quit_sig = true; - } else if ((sigio == SIGINT) || (sigio == SIGTERM)) { - exit_sig = true; - } - return; -} - -static int parse_SX1301_configuration(const char * conf_file) { - int i; - char param_name[32]; /* used to generate variable parameter names */ - const char *str; /* used to store string value from JSON object */ - const char conf_obj_name[] = "SX1301_conf"; - JSON_Value *root_val = NULL; - JSON_Object *conf_obj = NULL; - JSON_Object *conf_lbt_obj = NULL; - JSON_Object *conf_lbtchan_obj = NULL; - JSON_Value *val = NULL; - JSON_Array *conf_array = NULL; - struct lgw_conf_board_s boardconf; - struct lgw_conf_lbt_s lbtconf; - struct lgw_conf_rxrf_s rfconf; - struct lgw_conf_rxif_s ifconf; - uint32_t sf, bw, fdev; - - /* try to parse JSON */ - root_val = json_parse_file_with_comments(conf_file); - if (root_val == NULL) { - MSG("ERROR: %s is not a valid JSON file\n", conf_file); - exit(EXIT_FAILURE); - } - - /* point to the gateway configuration object */ - conf_obj = json_object_get_object(json_value_get_object(root_val), conf_obj_name); - if (conf_obj == NULL) { - MSG("INFO: %s does not contain a JSON object named %s\n", conf_file, conf_obj_name); - return -1; - } else { - MSG("INFO: %s does contain a JSON object named %s, parsing SX1301 parameters\n", conf_file, conf_obj_name); - } - - /* set board configuration */ - memset(&boardconf, 0, sizeof boardconf); /* initialize configuration structure */ - val = json_object_get_value(conf_obj, "lorawan_public"); /* fetch value (if possible) */ - if (json_value_get_type(val) == JSONBoolean) { - boardconf.lorawan_public = (bool)json_value_get_boolean(val); - } else { - MSG("WARNING: Data type for lorawan_public seems wrong, please check\n"); - boardconf.lorawan_public = false; - } - val = json_object_get_value(conf_obj, "clksrc"); /* fetch value (if possible) */ - if (json_value_get_type(val) == JSONNumber) { - boardconf.clksrc = (uint8_t)json_value_get_number(val); - } else { - MSG("WARNING: Data type for clksrc seems wrong, please check\n"); - boardconf.clksrc = 0; - } - MSG("INFO: lorawan_public %d, clksrc %d\n", boardconf.lorawan_public, boardconf.clksrc); - /* all parameters parsed, submitting configuration to the HAL */ - if (lgw_board_setconf(boardconf) != LGW_HAL_SUCCESS) { - MSG("ERROR: Failed to configure board\n"); - return -1; - } - - /* set LBT configuration */ - memset(&lbtconf, 0, sizeof lbtconf); /* initialize configuration structure */ - conf_lbt_obj = json_object_get_object(conf_obj, "lbt_cfg"); /* fetch value (if possible) */ - if (conf_lbt_obj == NULL) { - MSG("INFO: no configuration for LBT\n"); - } else { - val = json_object_get_value(conf_lbt_obj, "enable"); /* fetch value (if possible) */ - if (json_value_get_type(val) == JSONBoolean) { - lbtconf.enable = (bool)json_value_get_boolean(val); - } else { - MSG("WARNING: Data type for lbt_cfg.enable seems wrong, please check\n"); - lbtconf.enable = false; - } - if (lbtconf.enable == true) { - val = json_object_get_value(conf_lbt_obj, "rssi_target"); /* fetch value (if possible) */ - if (json_value_get_type(val) == JSONNumber) { - lbtconf.rssi_target = (int8_t)json_value_get_number(val); - } else { - MSG("WARNING: Data type for lbt_cfg.rssi_target seems wrong, please check\n"); - lbtconf.rssi_target = 0; - } - val = json_object_get_value(conf_lbt_obj, "sx127x_rssi_offset"); /* fetch value (if possible) */ - if (json_value_get_type(val) == JSONNumber) { - lbtconf.rssi_offset = (int8_t)json_value_get_number(val); - } else { - MSG("WARNING: Data type for lbt_cfg.sx127x_rssi_offset seems wrong, please check\n"); - lbtconf.rssi_offset = 0; - } - /* set LBT channels configuration */ - conf_array = json_object_get_array(conf_lbt_obj, "chan_cfg"); - if (conf_array != NULL) { - lbtconf.nb_channel = json_array_get_count( conf_array ); - MSG("INFO: %u LBT channels configured\n", lbtconf.nb_channel); - } - for (i = 0; i < (int)lbtconf.nb_channel; i++) { - /* Sanity check */ - if (i >= LBT_CHANNEL_FREQ_NB) - { - MSG("ERROR: LBT channel %d not supported, skip it\n", i ); - break; - } - /* Get LBT channel configuration object from array */ - conf_lbtchan_obj = json_array_get_object(conf_array, i); - - /* Channel frequency */ - val = json_object_dotget_value(conf_lbtchan_obj, "freq_hz"); /* fetch value (if possible) */ - if (json_value_get_type(val) == JSONNumber) { - lbtconf.channels[i].freq_hz = (uint32_t)json_value_get_number(val); - } else { - MSG("WARNING: Data type for lbt_cfg.channels[%d].freq_hz seems wrong, please check\n", i); - lbtconf.channels[i].freq_hz = 0; - } - - /* Channel scan time */ - val = json_object_dotget_value(conf_lbtchan_obj, "scan_time_us"); /* fetch value (if possible) */ - if (json_value_get_type(val) == JSONNumber) { - lbtconf.channels[i].scan_time_us = (uint16_t)json_value_get_number(val); - } else { - MSG("WARNING: Data type for lbt_cfg.channels[%d].scan_time_us seems wrong, please check\n", i); - lbtconf.channels[i].scan_time_us = 0; - } - } - - /* all parameters parsed, submitting configuration to the HAL */ - if (lgw_lbt_setconf(lbtconf) != LGW_HAL_SUCCESS) { - MSG("ERROR: Failed to configure LBT\n"); - return -1; - } - } else { - MSG("INFO: LBT is disabled\n"); - } - } - - /* set antenna gain configuration */ - val = json_object_get_value(conf_obj, "antenna_gain"); /* fetch value (if possible) */ - if (val != NULL) { - if (json_value_get_type(val) == JSONNumber) { - antenna_gain = (int8_t)json_value_get_number(val); - } else { - MSG("WARNING: Data type for antenna_gain seems wrong, please check\n"); - antenna_gain = 0; - } - } - MSG("INFO: antenna_gain %d dBi\n", antenna_gain); - - /* set configuration for tx gains */ - memset(&txlut, 0, sizeof txlut); /* initialize configuration structure */ - for (i = 0; i < TX_GAIN_LUT_SIZE_MAX; i++) { - snprintf(param_name, sizeof param_name, "tx_lut_%i", i); /* compose parameter path inside JSON structure */ - val = json_object_get_value(conf_obj, param_name); /* fetch value (if possible) */ - if (json_value_get_type(val) != JSONObject) { - MSG("INFO: no configuration for tx gain lut %i\n", i); - continue; - } - txlut.size++; /* update TX LUT size based on JSON object found in configuration file */ - /* there is an object to configure that TX gain index, let's parse it */ - snprintf(param_name, sizeof param_name, "tx_lut_%i.pa_gain", i); - val = json_object_dotget_value(conf_obj, param_name); - if (json_value_get_type(val) == JSONNumber) { - txlut.lut[i].pa_gain = (uint8_t)json_value_get_number(val); - } else { - MSG("WARNING: Data type for %s[%d] seems wrong, please check\n", param_name, i); - txlut.lut[i].pa_gain = 0; - } - snprintf(param_name, sizeof param_name, "tx_lut_%i.dac_gain", i); - val = json_object_dotget_value(conf_obj, param_name); - if (json_value_get_type(val) == JSONNumber) { - txlut.lut[i].dac_gain = (uint8_t)json_value_get_number(val); - } else { - txlut.lut[i].dac_gain = 3; /* This is the only dac_gain supported for now */ - } - snprintf(param_name, sizeof param_name, "tx_lut_%i.dig_gain", i); - val = json_object_dotget_value(conf_obj, param_name); - if (json_value_get_type(val) == JSONNumber) { - txlut.lut[i].dig_gain = (uint8_t)json_value_get_number(val); - } else { - MSG("WARNING: Data type for %s[%d] seems wrong, please check\n", param_name, i); - txlut.lut[i].dig_gain = 0; - } - snprintf(param_name, sizeof param_name, "tx_lut_%i.mix_gain", i); - val = json_object_dotget_value(conf_obj, param_name); - if (json_value_get_type(val) == JSONNumber) { - txlut.lut[i].mix_gain = (uint8_t)json_value_get_number(val); - } else { - MSG("WARNING: Data type for %s[%d] seems wrong, please check\n", param_name, i); - txlut.lut[i].mix_gain = 0; - } - snprintf(param_name, sizeof param_name, "tx_lut_%i.rf_power", i); - val = json_object_dotget_value(conf_obj, param_name); - if (json_value_get_type(val) == JSONNumber) { - txlut.lut[i].rf_power = (int8_t)json_value_get_number(val); - } else { - MSG("WARNING: Data type for %s[%d] seems wrong, please check\n", param_name, i); - txlut.lut[i].rf_power = 0; - } - } - /* all parameters parsed, submitting configuration to the HAL */ - if (txlut.size > 0) { - MSG("INFO: Configuring TX LUT with %u indexes\n", txlut.size); - if (lgw_txgain_setconf(&txlut) != LGW_HAL_SUCCESS) { - MSG("ERROR: Failed to configure concentrator TX Gain LUT\n"); - return -1; - } - } else { - MSG("WARNING: No TX gain LUT defined\n"); - } - - /* set configuration for RF chains */ - for (i = 0; i < LGW_RF_CHAIN_NB; ++i) { - memset(&rfconf, 0, sizeof rfconf); /* initialize configuration structure */ - snprintf(param_name, sizeof param_name, "radio_%i", i); /* compose parameter path inside JSON structure */ - val = json_object_get_value(conf_obj, param_name); /* fetch value (if possible) */ - if (json_value_get_type(val) != JSONObject) { - MSG("INFO: no configuration for radio %i\n", i); - continue; - } - /* there is an object to configure that radio, let's parse it */ - snprintf(param_name, sizeof param_name, "radio_%i.enable", i); - val = json_object_dotget_value(conf_obj, param_name); - if (json_value_get_type(val) == JSONBoolean) { - rfconf.enable = (bool)json_value_get_boolean(val); - } else { - rfconf.enable = false; - } - if (rfconf.enable == false) { /* radio disabled, nothing else to parse */ - MSG("INFO: radio %i disabled\n", i); - } else { /* radio enabled, will parse the other parameters */ - snprintf(param_name, sizeof param_name, "radio_%i.freq", i); - rfconf.freq_hz = (uint32_t)json_object_dotget_number(conf_obj, param_name); - snprintf(param_name, sizeof param_name, "radio_%i.rssi_offset", i); - rfconf.rssi_offset = (float)json_object_dotget_number(conf_obj, param_name); - snprintf(param_name, sizeof param_name, "radio_%i.type", i); - str = json_object_dotget_string(conf_obj, param_name); - if (!strncmp(str, "SX1255", 6)) { - rfconf.type = LGW_RADIO_TYPE_SX1255; - } else if (!strncmp(str, "SX1257", 6)) { - rfconf.type = LGW_RADIO_TYPE_SX1257; - } else { - MSG("WARNING: invalid radio type: %s (should be SX1255 or SX1257)\n", str); - } - snprintf(param_name, sizeof param_name, "radio_%i.tx_enable", i); - val = json_object_dotget_value(conf_obj, param_name); - if (json_value_get_type(val) == JSONBoolean) { - rfconf.tx_enable = (bool)json_value_get_boolean(val); - if (rfconf.tx_enable == true) { - /* tx is enabled on this rf chain, we need its frequency range */ - snprintf(param_name, sizeof param_name, "radio_%i.tx_freq_min", i); - tx_freq_min[i] = (uint32_t)json_object_dotget_number(conf_obj, param_name); - snprintf(param_name, sizeof param_name, "radio_%i.tx_freq_max", i); - tx_freq_max[i] = (uint32_t)json_object_dotget_number(conf_obj, param_name); - if ((tx_freq_min[i] == 0) || (tx_freq_max[i] == 0)) { - MSG("WARNING: no frequency range specified for TX rf chain %d\n", i); - } - /* ... and the notch filter frequency to be set */ - snprintf(param_name, sizeof param_name, "radio_%i.tx_notch_freq", i); - rfconf.tx_notch_freq = (uint32_t)json_object_dotget_number(conf_obj, param_name); - } - } else { - rfconf.tx_enable = false; - } - MSG("INFO: radio %i enabled (type %s), center frequency %u, RSSI offset %f, tx enabled %d, tx_notch_freq %u\n", i, str, rfconf.freq_hz, rfconf.rssi_offset, rfconf.tx_enable, rfconf.tx_notch_freq); - } - /* all parameters parsed, submitting configuration to the HAL */ - if (lgw_rxrf_setconf(i, rfconf) != LGW_HAL_SUCCESS) { - MSG("ERROR: invalid configuration for radio %i\n", i); - return -1; - } - } - - /* set configuration for Lora multi-SF channels (bandwidth cannot be set) */ - for (i = 0; i < LGW_MULTI_NB; ++i) { - memset(&ifconf, 0, sizeof ifconf); /* initialize configuration structure */ - snprintf(param_name, sizeof param_name, "chan_multiSF_%i", i); /* compose parameter path inside JSON structure */ - val = json_object_get_value(conf_obj, param_name); /* fetch value (if possible) */ - if (json_value_get_type(val) != JSONObject) { - MSG("INFO: no configuration for Lora multi-SF channel %i\n", i); - continue; - } - /* there is an object to configure that Lora multi-SF channel, let's parse it */ - snprintf(param_name, sizeof param_name, "chan_multiSF_%i.enable", i); - val = json_object_dotget_value(conf_obj, param_name); - if (json_value_get_type(val) == JSONBoolean) { - ifconf.enable = (bool)json_value_get_boolean(val); - } else { - ifconf.enable = false; - } - if (ifconf.enable == false) { /* Lora multi-SF channel disabled, nothing else to parse */ - MSG("INFO: Lora multi-SF channel %i disabled\n", i); - } else { /* Lora multi-SF channel enabled, will parse the other parameters */ - snprintf(param_name, sizeof param_name, "chan_multiSF_%i.radio", i); - ifconf.rf_chain = (uint32_t)json_object_dotget_number(conf_obj, param_name); - snprintf(param_name, sizeof param_name, "chan_multiSF_%i.if", i); - ifconf.freq_hz = (int32_t)json_object_dotget_number(conf_obj, param_name); - // TODO: handle individual SF enabling and disabling (spread_factor) - MSG("INFO: Lora multi-SF channel %i> radio %i, IF %i Hz, 125 kHz bw, SF 7 to 12\n", i, ifconf.rf_chain, ifconf.freq_hz); - } - /* all parameters parsed, submitting configuration to the HAL */ - if (lgw_rxif_setconf(i, ifconf) != LGW_HAL_SUCCESS) { - MSG("ERROR: invalid configuration for Lora multi-SF channel %i\n", i); - return -1; - } - } - - /* set configuration for Lora standard channel */ - memset(&ifconf, 0, sizeof ifconf); /* initialize configuration structure */ - val = json_object_get_value(conf_obj, "chan_Lora_std"); /* fetch value (if possible) */ - if (json_value_get_type(val) != JSONObject) { - MSG("INFO: no configuration for Lora standard channel\n"); - } else { - val = json_object_dotget_value(conf_obj, "chan_Lora_std.enable"); - if (json_value_get_type(val) == JSONBoolean) { - ifconf.enable = (bool)json_value_get_boolean(val); - } else { - ifconf.enable = false; - } - if (ifconf.enable == false) { - MSG("INFO: Lora standard channel %i disabled\n", i); - } else { - ifconf.rf_chain = (uint32_t)json_object_dotget_number(conf_obj, "chan_Lora_std.radio"); - ifconf.freq_hz = (int32_t)json_object_dotget_number(conf_obj, "chan_Lora_std.if"); - bw = (uint32_t)json_object_dotget_number(conf_obj, "chan_Lora_std.bandwidth"); - switch(bw) { - case 500000: ifconf.bandwidth = BW_500KHZ; break; - case 250000: ifconf.bandwidth = BW_250KHZ; break; - case 125000: ifconf.bandwidth = BW_125KHZ; break; - default: ifconf.bandwidth = BW_UNDEFINED; - } - sf = (uint32_t)json_object_dotget_number(conf_obj, "chan_Lora_std.spread_factor"); - switch(sf) { - case 7: ifconf.datarate = DR_LORA_SF7; break; - case 8: ifconf.datarate = DR_LORA_SF8; break; - case 9: ifconf.datarate = DR_LORA_SF9; break; - case 10: ifconf.datarate = DR_LORA_SF10; break; - case 11: ifconf.datarate = DR_LORA_SF11; break; - case 12: ifconf.datarate = DR_LORA_SF12; break; - default: ifconf.datarate = DR_UNDEFINED; - } - MSG("INFO: Lora std channel> radio %i, IF %i Hz, %u Hz bw, SF %u\n", ifconf.rf_chain, ifconf.freq_hz, bw, sf); - } - if (lgw_rxif_setconf(8, ifconf) != LGW_HAL_SUCCESS) { - MSG("ERROR: invalid configuration for Lora standard channel\n"); - return -1; - } - } - - /* set configuration for FSK channel */ - memset(&ifconf, 0, sizeof ifconf); /* initialize configuration structure */ - val = json_object_get_value(conf_obj, "chan_FSK"); /* fetch value (if possible) */ - if (json_value_get_type(val) != JSONObject) { - MSG("INFO: no configuration for FSK channel\n"); - } else { - val = json_object_dotget_value(conf_obj, "chan_FSK.enable"); - if (json_value_get_type(val) == JSONBoolean) { - ifconf.enable = (bool)json_value_get_boolean(val); - } else { - ifconf.enable = false; - } - if (ifconf.enable == false) { - MSG("INFO: FSK channel %i disabled\n", i); - } else { - ifconf.rf_chain = (uint32_t)json_object_dotget_number(conf_obj, "chan_FSK.radio"); - ifconf.freq_hz = (int32_t)json_object_dotget_number(conf_obj, "chan_FSK.if"); - bw = (uint32_t)json_object_dotget_number(conf_obj, "chan_FSK.bandwidth"); - fdev = (uint32_t)json_object_dotget_number(conf_obj, "chan_FSK.freq_deviation"); - ifconf.datarate = (uint32_t)json_object_dotget_number(conf_obj, "chan_FSK.datarate"); - - /* if chan_FSK.bandwidth is set, it has priority over chan_FSK.freq_deviation */ - if ((bw == 0) && (fdev != 0)) { - bw = 2 * fdev + ifconf.datarate; - } - if (bw == 0) ifconf.bandwidth = BW_UNDEFINED; - else if (bw <= 7800) ifconf.bandwidth = BW_7K8HZ; - else if (bw <= 15600) ifconf.bandwidth = BW_15K6HZ; - else if (bw <= 31200) ifconf.bandwidth = BW_31K2HZ; - else if (bw <= 62500) ifconf.bandwidth = BW_62K5HZ; - else if (bw <= 125000) ifconf.bandwidth = BW_125KHZ; - else if (bw <= 250000) ifconf.bandwidth = BW_250KHZ; - else if (bw <= 500000) ifconf.bandwidth = BW_500KHZ; - else ifconf.bandwidth = BW_UNDEFINED; - - MSG("INFO: FSK channel> radio %i, IF %i Hz, %u Hz bw, %u bps datarate\n", ifconf.rf_chain, ifconf.freq_hz, bw, ifconf.datarate); - } - if (lgw_rxif_setconf(9, ifconf) != LGW_HAL_SUCCESS) { - MSG("ERROR: invalid configuration for FSK channel\n"); - return -1; - } - } - json_value_free(root_val); - - return 0; -} - -static int parse_gateway_configuration(const char * conf_file) { - const char conf_obj_name[] = "gateway_conf"; - JSON_Value *root_val; - JSON_Object *conf_obj = NULL; - JSON_Value *val = NULL; /* needed to detect the absence of some fields */ - const char *str; /* pointer to sub-strings in the JSON data */ - unsigned long long ull = 0; - - /* try to parse JSON */ - root_val = json_parse_file_with_comments(conf_file); - if (root_val == NULL) { - MSG("ERROR: %s is not a valid JSON file\n", conf_file); - exit(EXIT_FAILURE); - } - - /* point to the gateway configuration object */ - conf_obj = json_object_get_object(json_value_get_object(root_val), conf_obj_name); - if (conf_obj == NULL) { - MSG("INFO: %s does not contain a JSON object named %s\n", conf_file, conf_obj_name); - return -1; - } else { - MSG("INFO: %s does contain a JSON object named %s, parsing gateway parameters\n", conf_file, conf_obj_name); - } - - /* gateway unique identifier (aka MAC address) (optional) */ - str = json_object_get_string(conf_obj, "gateway_ID"); - if (str != NULL) { - sscanf(str, "%llx", &ull); - lgwm = ull; - MSG("INFO: gateway MAC address is configured to %016llX\n", ull); - } - - /* server hostname or IP address (optional) */ - str = json_object_get_string(conf_obj, "server_address"); - if (str != NULL) { - strncpy(serv_addr, str, sizeof(serv_addr) - 1); - MSG("INFO: server hostname or IP address is configured to \"%s\"\n", serv_addr); - } - - /* get up and down ports (optional) */ - val = json_object_get_value(conf_obj, "serv_port_up"); - if (val != NULL) { - snprintf(serv_port_up, sizeof serv_port_up, "%u", (uint16_t)json_value_get_number(val)); - MSG("INFO: upstream port is configured to \"%s\"\n", serv_port_up); - } - val = json_object_get_value(conf_obj, "serv_port_down"); - if (val != NULL) { - snprintf(serv_port_down, sizeof serv_port_down, "%u", (uint16_t)json_value_get_number(val)); - MSG("INFO: downstream port is configured to \"%s\"\n", serv_port_down); - } - - /* get keep-alive interval (in seconds) for downstream (optional) */ - val = json_object_get_value(conf_obj, "keepalive_interval"); - if (val != NULL) { - keepalive_time = (int)json_value_get_number(val); - MSG("INFO: downstream keep-alive interval is configured to %u seconds\n", keepalive_time); - } - - /* get interval (in seconds) for statistics display (optional) */ - val = json_object_get_value(conf_obj, "stat_interval"); - if (val != NULL) { - stat_interval = (unsigned)json_value_get_number(val); - MSG("INFO: statistics display interval is configured to %u seconds\n", stat_interval); - } - - /* get time-out value (in ms) for upstream datagrams (optional) */ - val = json_object_get_value(conf_obj, "push_timeout_ms"); - if (val != NULL) { - push_timeout_half.tv_usec = 500 * (long int)json_value_get_number(val); - MSG("INFO: upstream PUSH_DATA time-out is configured to %u ms\n", (unsigned)(push_timeout_half.tv_usec / 500)); - } - - /* packet filtering parameters */ - val = json_object_get_value(conf_obj, "forward_crc_valid"); - if (json_value_get_type(val) == JSONBoolean) { - fwd_valid_pkt = (bool)json_value_get_boolean(val); - } - MSG("INFO: packets received with a valid CRC will%s be forwarded\n", (fwd_valid_pkt ? "" : " NOT")); - val = json_object_get_value(conf_obj, "forward_crc_error"); - if (json_value_get_type(val) == JSONBoolean) { - fwd_error_pkt = (bool)json_value_get_boolean(val); - } - MSG("INFO: packets received with a CRC error will%s be forwarded\n", (fwd_error_pkt ? "" : " NOT")); - val = json_object_get_value(conf_obj, "forward_crc_disabled"); - if (json_value_get_type(val) == JSONBoolean) { - fwd_nocrc_pkt = (bool)json_value_get_boolean(val); - } - MSG("INFO: packets received with no CRC will%s be forwarded\n", (fwd_nocrc_pkt ? "" : " NOT")); - - /* GPS module TTY path (optional) */ - str = json_object_get_string(conf_obj, "gps_tty_path"); - if (str != NULL) { - strncpy(gps_tty_path, str, sizeof(gps_tty_path) - 1); - MSG("INFO: GPS serial port path is configured to \"%s\"\n", gps_tty_path); - } - - /* get reference coordinates */ - val = json_object_get_value(conf_obj, "ref_latitude"); - if (val != NULL) { - reference_coord.lat = (double)json_value_get_number(val); - MSG("INFO: Reference latitude is configured to %f deg\n", reference_coord.lat); - } - val = json_object_get_value(conf_obj, "ref_longitude"); - if (val != NULL) { - reference_coord.lon = (double)json_value_get_number(val); - MSG("INFO: Reference longitude is configured to %f deg\n", reference_coord.lon); - } - val = json_object_get_value(conf_obj, "ref_altitude"); - if (val != NULL) { - reference_coord.alt = (short)json_value_get_number(val); - MSG("INFO: Reference altitude is configured to %i meters\n", reference_coord.alt); - } - - /* Gateway GPS coordinates hardcoding (aka. faking) option */ - val = json_object_get_value(conf_obj, "fake_gps"); - if (json_value_get_type(val) == JSONBoolean) { - gps_fake_enable = (bool)json_value_get_boolean(val); - if (gps_fake_enable == true) { - MSG("INFO: fake GPS is enabled\n"); - } else { - MSG("INFO: fake GPS is disabled\n"); - } - } - - /* Beacon signal period (optional) */ - val = json_object_get_value(conf_obj, "beacon_period"); - if (val != NULL) { - beacon_period = (uint32_t)json_value_get_number(val); - if ((beacon_period > 0) && (beacon_period < 6)) { - MSG("ERROR: invalid configuration for Beacon period, must be >= 6s\n"); - return -1; - } else { - MSG("INFO: Beaconing period is configured to %u seconds\n", beacon_period); - } - } - - /* Beacon TX frequency (optional) */ - val = json_object_get_value(conf_obj, "beacon_freq_hz"); - if (val != NULL) { - beacon_freq_hz = (uint32_t)json_value_get_number(val); - MSG("INFO: Beaconing signal will be emitted at %u Hz\n", beacon_freq_hz); - } - - /* Number of beacon channels (optional) */ - val = json_object_get_value(conf_obj, "beacon_freq_nb"); - if (val != NULL) { - beacon_freq_nb = (uint8_t)json_value_get_number(val); - MSG("INFO: Beaconing channel number is set to %u\n", beacon_freq_nb); - } - - /* Frequency step between beacon channels (optional) */ - val = json_object_get_value(conf_obj, "beacon_freq_step"); - if (val != NULL) { - beacon_freq_step = (uint32_t)json_value_get_number(val); - MSG("INFO: Beaconing channel frequency step is set to %uHz\n", beacon_freq_step); - } - - /* Beacon datarate (optional) */ - val = json_object_get_value(conf_obj, "beacon_datarate"); - if (val != NULL) { - beacon_datarate = (uint8_t)json_value_get_number(val); - MSG("INFO: Beaconing datarate is set to SF%d\n", beacon_datarate); - } - - /* Beacon modulation bandwidth (optional) */ - val = json_object_get_value(conf_obj, "beacon_bw_hz"); - if (val != NULL) { - beacon_bw_hz = (uint32_t)json_value_get_number(val); - MSG("INFO: Beaconing modulation bandwidth is set to %dHz\n", beacon_bw_hz); - } - - /* Beacon TX power (optional) */ - val = json_object_get_value(conf_obj, "beacon_power"); - if (val != NULL) { - beacon_power = (int8_t)json_value_get_number(val); - MSG("INFO: Beaconing TX power is set to %ddBm\n", beacon_power); - } - - /* Beacon information descriptor (optional) */ - val = json_object_get_value(conf_obj, "beacon_infodesc"); - if (val != NULL) { - beacon_infodesc = (uint8_t)json_value_get_number(val); - MSG("INFO: Beaconing information descriptor is set to %u\n", beacon_infodesc); - } - - /* Auto-quit threshold (optional) */ - val = json_object_get_value(conf_obj, "autoquit_threshold"); - if (val != NULL) { - autoquit_threshold = (uint32_t)json_value_get_number(val); - MSG("INFO: Auto-quit after %u non-acknowledged PULL_DATA\n", autoquit_threshold); - } - - /* free JSON parsing data structure */ - json_value_free(root_val); - return 0; -} - -static uint16_t crc16(const uint8_t * data, unsigned size) { - const uint16_t crc_poly = 0x1021; - const uint16_t init_val = 0x0000; - uint16_t x = init_val; - unsigned i, j; - - if (data == NULL) { - return 0; - } - - for (i=0; i>32))); - net_mac_l = htonl((uint32_t)(0xFFFFFFFF & lgwm )); - - /* prepare hints to open network sockets */ - memset(&hints, 0, sizeof hints); - hints.ai_family = AF_INET; /* WA: Forcing IPv4 as AF_UNSPEC makes connection on localhost to fail */ - hints.ai_socktype = SOCK_DGRAM; - - /* look for server address w/ upstream port */ - i = getaddrinfo(serv_addr, serv_port_up, &hints, &result); - if (i != 0) { - MSG("ERROR: [up] getaddrinfo on address %s (PORT %s) returned %s\n", serv_addr, serv_port_up, gai_strerror(i)); - exit(EXIT_FAILURE); - } - - /* try to open socket for upstream traffic */ - for (q=result; q!=NULL; q=q->ai_next) { - sock_up = socket(q->ai_family, q->ai_socktype,q->ai_protocol); - if (sock_up == -1) continue; /* try next field */ - else break; /* success, get out of loop */ - } - if (q == NULL) { - MSG("ERROR: [up] failed to open socket to any of server %s addresses (port %s)\n", serv_addr, serv_port_up); - 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); - MSG("INFO: [up] result %i host:%s service:%s\n", i, host_name, port_name); - ++i; - } - exit(EXIT_FAILURE); - } - - /* connect so we can send/receive packet with the server only */ - i = connect(sock_up, q->ai_addr, q->ai_addrlen); - if (i != 0) { - MSG("ERROR: [up] connect returned %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - freeaddrinfo(result); - - /* 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)); - exit(EXIT_FAILURE); - } - - /* try to open socket for downstream traffic */ - for (q=result; q!=NULL; q=q->ai_next) { - sock_down = socket(q->ai_family, q->ai_socktype,q->ai_protocol); - if (sock_down == -1) continue; /* try next field */ - 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); - 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); - MSG("INFO: [down] result %i host:%s service:%s\n", i, host_name, port_name); - ++i; - } - exit(EXIT_FAILURE); - } - - /* connect so we can send/receive packet with the server only */ - i = connect(sock_down, q->ai_addr, q->ai_addrlen); - if (i != 0) { - MSG("ERROR: [down] connect returned %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - freeaddrinfo(result); - - /* starting the concentrator */ - i = lgw_start(); - if (i == LGW_HAL_SUCCESS) { - MSG("INFO: [main] concentrator started, packet can now be received\n"); - } else { - MSG("ERROR: [main] failed to start the concentrator\n"); - exit(EXIT_FAILURE); - } - - /* spawn threads to manage upstream and downstream */ - 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); - 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); - if (i != 0) { - MSG("ERROR: [main] impossible to create JIT thread\n"); - exit(EXIT_FAILURE); - } - i = pthread_create( &thrid_timersync, NULL, (void * (*)(void *))thread_timersync, NULL); - if (i != 0) { - MSG("ERROR: [main] impossible to create Timer Sync 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); - 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); - if (i != 0) { - MSG("ERROR: [main] impossible to create validation thread\n"); - exit(EXIT_FAILURE); - } - } - - /* configure signal handling */ - sigemptyset(&sigact.sa_mask); - sigact.sa_flags = 0; - sigact.sa_handler = sig_handler; - sigaction(SIGQUIT, &sigact, NULL); /* Ctrl-\ */ - sigaction(SIGINT, &sigact, NULL); /* Ctrl-C */ - sigaction(SIGTERM, &sigact, NULL); /* default "kill" command */ - - /* main loop task : statistics collection */ - while (!exit_sig && !quit_sig) { - /* wait for next reporting interval */ - wait_ms(1000 * stat_interval); - - /* get timestamp for statistics */ - t = time(NULL); - strftime(stat_timestamp, sizeof stat_timestamp, "%F %T %Z", gmtime(&t)); - - /* access upstream statistics, copy and reset them */ - pthread_mutex_lock(&mx_meas_up); - cp_nb_rx_rcv = meas_nb_rx_rcv; - cp_nb_rx_ok = meas_nb_rx_ok; - cp_nb_rx_bad = meas_nb_rx_bad; - cp_nb_rx_nocrc = meas_nb_rx_nocrc; - cp_up_pkt_fwd = meas_up_pkt_fwd; - cp_up_network_byte = meas_up_network_byte; - cp_up_payload_byte = meas_up_payload_byte; - cp_up_dgram_sent = meas_up_dgram_sent; - cp_up_ack_rcv = meas_up_ack_rcv; - meas_nb_rx_rcv = 0; - meas_nb_rx_ok = 0; - meas_nb_rx_bad = 0; - meas_nb_rx_nocrc = 0; - meas_up_pkt_fwd = 0; - meas_up_network_byte = 0; - meas_up_payload_byte = 0; - meas_up_dgram_sent = 0; - meas_up_ack_rcv = 0; - pthread_mutex_unlock(&mx_meas_up); - if (cp_nb_rx_rcv > 0) { - rx_ok_ratio = (float)cp_nb_rx_ok / (float)cp_nb_rx_rcv; - rx_bad_ratio = (float)cp_nb_rx_bad / (float)cp_nb_rx_rcv; - rx_nocrc_ratio = (float)cp_nb_rx_nocrc / (float)cp_nb_rx_rcv; - } else { - rx_ok_ratio = 0.0; - rx_bad_ratio = 0.0; - rx_nocrc_ratio = 0.0; - } - if (cp_up_dgram_sent > 0) { - up_ack_ratio = (float)cp_up_ack_rcv / (float)cp_up_dgram_sent; - } else { - up_ack_ratio = 0.0; - } - - /* access downstream statistics, copy and reset them */ - pthread_mutex_lock(&mx_meas_dw); - cp_dw_pull_sent = meas_dw_pull_sent; - cp_dw_ack_rcv = meas_dw_ack_rcv; - cp_dw_dgram_rcv = meas_dw_dgram_rcv; - cp_dw_network_byte = meas_dw_network_byte; - cp_dw_payload_byte = meas_dw_payload_byte; - cp_nb_tx_ok = meas_nb_tx_ok; - cp_nb_tx_fail = meas_nb_tx_fail; - cp_nb_tx_requested += meas_nb_tx_requested; - cp_nb_tx_rejected_collision_packet += meas_nb_tx_rejected_collision_packet; - cp_nb_tx_rejected_collision_beacon += meas_nb_tx_rejected_collision_beacon; - cp_nb_tx_rejected_too_late += meas_nb_tx_rejected_too_late; - cp_nb_tx_rejected_too_early += meas_nb_tx_rejected_too_early; - cp_nb_beacon_queued += meas_nb_beacon_queued; - cp_nb_beacon_sent += meas_nb_beacon_sent; - cp_nb_beacon_rejected += meas_nb_beacon_rejected; - meas_dw_pull_sent = 0; - meas_dw_ack_rcv = 0; - meas_dw_dgram_rcv = 0; - meas_dw_network_byte = 0; - meas_dw_payload_byte = 0; - meas_nb_tx_ok = 0; - meas_nb_tx_fail = 0; - meas_nb_tx_requested = 0; - meas_nb_tx_rejected_collision_packet = 0; - meas_nb_tx_rejected_collision_beacon = 0; - meas_nb_tx_rejected_too_late = 0; - meas_nb_tx_rejected_too_early = 0; - meas_nb_beacon_queued = 0; - meas_nb_beacon_sent = 0; - meas_nb_beacon_rejected = 0; - pthread_mutex_unlock(&mx_meas_dw); - if (cp_dw_pull_sent > 0) { - dw_ack_ratio = (float)cp_dw_ack_rcv / (float)cp_dw_pull_sent; - } else { - dw_ack_ratio = 0.0; - } - - /* access GPS statistics, copy them */ - if (gps_enabled == true) { - pthread_mutex_lock(&mx_meas_gps); - coord_ok = gps_coord_valid; - cp_gps_coord = meas_gps_coord; - pthread_mutex_unlock(&mx_meas_gps); - } - - /* overwrite with reference coordinates if function is enabled */ - if (gps_fake_enable == true) { - cp_gps_coord = reference_coord; - } - - /* display a report */ - printf("\n##### %s #####\n", stat_timestamp); - printf("### [UPSTREAM] ###\n"); - printf("# RF packets received by concentrator: %u\n", cp_nb_rx_rcv); - printf("# CRC_OK: %.2f%%, CRC_FAIL: %.2f%%, NO_CRC: %.2f%%\n", 100.0 * rx_ok_ratio, 100.0 * rx_bad_ratio, 100.0 * rx_nocrc_ratio); - printf("# RF packets forwarded: %u (%u bytes)\n", cp_up_pkt_fwd, cp_up_payload_byte); - printf("# PUSH_DATA datagrams sent: %u (%u bytes)\n", cp_up_dgram_sent, cp_up_network_byte); - printf("# PUSH_DATA acknowledged: %.2f%%\n", 100.0 * up_ack_ratio); - printf("### [DOWNSTREAM] ###\n"); - printf("# PULL_DATA sent: %u (%.2f%% acknowledged)\n", cp_dw_pull_sent, 100.0 * dw_ack_ratio); - printf("# PULL_RESP(onse) datagrams received: %u (%u bytes)\n", cp_dw_dgram_rcv, cp_dw_network_byte); - printf("# RF packets sent to concentrator: %u (%u bytes)\n", (cp_nb_tx_ok+cp_nb_tx_fail), cp_dw_payload_byte); - printf("# TX errors: %u\n", cp_nb_tx_fail); - if (cp_nb_tx_requested != 0 ) { - printf("# TX rejected (collision packet): %.2f%% (req:%u, rej:%u)\n", 100.0 * cp_nb_tx_rejected_collision_packet / cp_nb_tx_requested, cp_nb_tx_requested, cp_nb_tx_rejected_collision_packet); - printf("# TX rejected (collision beacon): %.2f%% (req:%u, rej:%u)\n", 100.0 * cp_nb_tx_rejected_collision_beacon / cp_nb_tx_requested, cp_nb_tx_requested, cp_nb_tx_rejected_collision_beacon); - printf("# TX rejected (too late): %.2f%% (req:%u, rej:%u)\n", 100.0 * cp_nb_tx_rejected_too_late / cp_nb_tx_requested, cp_nb_tx_requested, cp_nb_tx_rejected_too_late); - printf("# TX rejected (too early): %.2f%% (req:%u, rej:%u)\n", 100.0 * cp_nb_tx_rejected_too_early / cp_nb_tx_requested, cp_nb_tx_requested, cp_nb_tx_rejected_too_early); - } - printf("# BEACON queued: %u\n", cp_nb_beacon_queued); - printf("# BEACON sent so far: %u\n", cp_nb_beacon_sent); - printf("# BEACON rejected: %u\n", cp_nb_beacon_rejected); - printf("### [JIT] ###\n"); - /* get timestamp captured on PPM pulse */ - pthread_mutex_lock(&mx_concent); - i = lgw_get_trigcnt(&trig_tstamp); - pthread_mutex_unlock(&mx_concent); - if (i != LGW_HAL_SUCCESS) { - printf("# SX1301 time (PPS): unknown\n"); - } else { - printf("# SX1301 time (PPS): %u\n", trig_tstamp); - } - jit_print_queue (&jit_queue, false, DEBUG_LOG); - printf("### [GPS] ###\n"); - if (gps_enabled == true) { - /* no need for mutex, display is not critical */ - if (gps_ref_valid == true) { - printf("# Valid time reference (age: %li sec)\n", (long)difftime(time(NULL), time_reference_gps.systime)); - } else { - printf("# Invalid time reference (age: %li sec)\n", (long)difftime(time(NULL), time_reference_gps.systime)); - } - if (coord_ok == true) { - printf("# GPS coordinates: latitude %.5f, longitude %.5f, altitude %i m\n", cp_gps_coord.lat, cp_gps_coord.lon, cp_gps_coord.alt); - } else { - printf("# no valid GPS coordinates available yet\n"); - } - } else if (gps_fake_enable == true) { - printf("# GPS *FAKE* coordinates: latitude %.5f, longitude %.5f, altitude %i m\n", cp_gps_coord.lat, cp_gps_coord.lon, cp_gps_coord.alt); - } else { - printf("# GPS sync is disabled\n"); - } - printf("##### END #####\n"); - - /* generate a JSON report (will be sent to server by upstream thread) */ - pthread_mutex_lock(&mx_stat_rep); - if (((gps_enabled == true) && (coord_ok == true)) || (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); - } 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); - } - 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 */ - pthread_cancel(thrid_timersync); /* don't wait for timer sync thread */ - if (gps_enabled == true) { - pthread_cancel(thrid_gps); /* don't wait for GPS thread */ - pthread_cancel(thrid_valid); /* don't wait for validation thread */ - - i = lgw_gps_disable(gps_tty_fd); - if (i == LGW_HAL_SUCCESS) { - MSG("INFO: GPS closed successfully\n"); - } else { - MSG("WARNING: failed to close GPS successfully\n"); - } - } - - /* if an exit signal was received, try to quit properly */ - if (exit_sig) { - /* shut down network sockets */ - shutdown(sock_up, SHUT_RDWR); - shutdown(sock_down, SHUT_RDWR); - /* stop the hardware */ - i = lgw_stop(); - if (i == LGW_HAL_SUCCESS) { - MSG("INFO: concentrator stopped successfully\n"); - } else { - MSG("WARNING: failed to stop concentrator successfully\n"); - } - } - - MSG("INFO: Exiting packet forwarder program\n"); - exit(EXIT_SUCCESS); -} - -/* -------------------------------------------------------------------------- */ -/* --- THREAD 1: RECEIVING PACKETS AND FORWARDING THEM ---------------------- */ - -void thread_up(void) { - int i, j; /* loop variables */ - unsigned pkt_in_dgram; /* nb on Lora packet in the current datagram */ - - /* allocate memory for packet fetching and processing */ - struct lgw_pkt_rx_s rxpkt[NB_PKT_MAX]; /* array containing inbound packets + metadata */ - struct lgw_pkt_rx_s *p; /* pointer on a RX packet */ - int nb_pkt; - - /* local copy of GPS time reference */ - bool ref_ok = false; /* determine if GPS time reference must be used or not */ - struct tref local_ref; /* time reference used for UTC <-> timestamp conversion */ - - /* data buffers */ - uint8_t buff_up[TX_BUFF_SIZE]; /* buffer to compose the upstream packet */ - int buff_index; - uint8_t buff_ack[32]; /* buffer to receive acknowledges */ - - /* protocol variables */ - uint8_t token_h; /* random token for acknowledgement matching */ - uint8_t token_l; /* random token for acknowledgement matching */ - - /* ping measurement variables */ - struct timespec send_time; - struct timespec recv_time; - - /* GPS synchronization variables */ - struct timespec pkt_utc_time; - struct tm * x; /* broken-up UTC time */ - struct timespec pkt_gps_time; - uint64_t pkt_gps_time_ms; - - /* report management variable */ - bool send_report = false; - - /* mote info variables */ - uint32_t mote_addr = 0; - uint16_t mote_fcnt = 0; - - /* set upstream socket RX timeout */ - i = setsockopt(sock_up, SOL_SOCKET, SO_RCVTIMEO, (void *)&push_timeout_half, sizeof push_timeout_half); - if (i != 0) { - MSG("ERROR: [up] setsockopt returned %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - - /* pre-fill the data buffer with fixed fields */ - buff_up[0] = PROTOCOL_VERSION; - buff_up[3] = PKT_PUSH_DATA; - *(uint32_t *)(buff_up + 4) = net_mac_h; - *(uint32_t *)(buff_up + 8) = net_mac_l; - - while (!exit_sig && !quit_sig) { - - /* fetch packets */ - pthread_mutex_lock(&mx_concent); - nb_pkt = lgw_receive(NB_PKT_MAX, rxpkt); - pthread_mutex_unlock(&mx_concent); - if (nb_pkt == LGW_HAL_ERROR) { - MSG("ERROR: [up] failed packet fetch, exiting\n"); - exit(EXIT_FAILURE); - } - - /* check if there are status report to send */ - send_report = report_ready; /* copy the variable so it doesn't change mid-function */ - /* no mutex, we're only reading */ - - /* wait a short time if no packets, nor status report */ - if ((nb_pkt == 0) && (send_report == false)) { - wait_ms(FETCH_SLEEP_MS); - continue; - } - - /* get a copy of GPS time reference (avoid 1 mutex per packet) */ - if ((nb_pkt > 0) && (gps_enabled == true)) { - pthread_mutex_lock(&mx_timeref); - ref_ok = gps_ref_valid; - local_ref = time_reference_gps; - pthread_mutex_unlock(&mx_timeref); - } else { - ref_ok = false; - } - - /* start composing datagram with the header */ - token_h = (uint8_t)rand(); /* random token */ - token_l = (uint8_t)rand(); /* random token */ - buff_up[1] = token_h; - buff_up[2] = token_l; - buff_index = 12; /* 12-byte header */ - - /* start of JSON structure */ - memcpy((void *)(buff_up + buff_index), (void *)"{\"rxpk\":[", 9); - buff_index += 9; - - /* serialize Lora packets metadata and payload */ - pkt_in_dgram = 0; - for (i=0; i < nb_pkt; ++i) { - p = &rxpkt[i]; - - /* Get mote information from current packet (addr, fcnt) */ - /* FHDR - DevAddr */ - mote_addr = p->payload[1]; - mote_addr |= p->payload[2] << 8; - mote_addr |= p->payload[3] << 16; - mote_addr |= p->payload[4] << 24; - /* FHDR - FCnt */ - mote_fcnt = p->payload[6]; - mote_fcnt |= p->payload[7] << 8; - - /* basic packet filtering */ - pthread_mutex_lock(&mx_meas_up); - meas_nb_rx_rcv += 1; - switch(p->status) { - case STAT_CRC_OK: - meas_nb_rx_ok += 1; - printf( "\nINFO: Received pkt from mote: %08X (fcnt=%u)\n", mote_addr, mote_fcnt ); - if (!fwd_valid_pkt) { - pthread_mutex_unlock(&mx_meas_up); - continue; /* skip that packet */ - } - break; - case STAT_CRC_BAD: - meas_nb_rx_bad += 1; - if (!fwd_error_pkt) { - pthread_mutex_unlock(&mx_meas_up); - continue; /* skip that packet */ - } - break; - case STAT_NO_CRC: - meas_nb_rx_nocrc += 1; - if (!fwd_nocrc_pkt) { - pthread_mutex_unlock(&mx_meas_up); - continue; /* skip that packet */ - } - break; - default: - MSG("WARNING: [up] received packet with unknown status %u (size %u, modulation %u, BW %u, DR %u, RSSI %.1f)\n", p->status, p->size, p->modulation, p->bandwidth, p->datarate, p->rssi); - pthread_mutex_unlock(&mx_meas_up); - continue; /* skip that packet */ - // exit(EXIT_FAILURE); - } - meas_up_pkt_fwd += 1; - meas_up_payload_byte += p->size; - pthread_mutex_unlock(&mx_meas_up); - - /* Start of packet, add inter-packet separator if necessary */ - if (pkt_in_dgram == 0) { - buff_up[buff_index] = '{'; - ++buff_index; - } else { - buff_up[buff_index] = ','; - buff_up[buff_index+1] = '{'; - buff_index += 2; - } - - /* RAW timestamp, 8-17 useful chars */ - j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, "\"tmst\":%u", p->count_us); - if (j > 0) { - buff_index += j; - } else { - MSG("ERROR: [up] snprintf failed line %u\n", (__LINE__ - 4)); - exit(EXIT_FAILURE); - } - - /* Packet RX time (GPS based), 37 useful chars */ - if (ref_ok == true) { - /* convert packet timestamp to UTC absolute time */ - j = lgw_cnt2utc(local_ref, p->count_us, &pkt_utc_time); - if (j == LGW_GPS_SUCCESS) { - /* split the UNIX timestamp to its calendar components */ - x = gmtime(&(pkt_utc_time.tv_sec)); - j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, ",\"time\":\"%04i-%02i-%02iT%02i:%02i:%02i.%06liZ\"", (x->tm_year)+1900, (x->tm_mon)+1, x->tm_mday, x->tm_hour, x->tm_min, x->tm_sec, (pkt_utc_time.tv_nsec)/1000); /* ISO 8601 format */ - if (j > 0) { - buff_index += j; - } else { - MSG("ERROR: [up] snprintf failed line %u\n", (__LINE__ - 4)); - exit(EXIT_FAILURE); - } - } - /* convert packet timestamp to GPS absolute time */ - j = lgw_cnt2gps(local_ref, p->count_us, &pkt_gps_time); - if (j == LGW_GPS_SUCCESS) { - pkt_gps_time_ms = pkt_gps_time.tv_sec * 1E3 + pkt_gps_time.tv_nsec / 1E6; - j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, ",\"tmms\":%llu", - pkt_gps_time_ms); /* GPS time in milliseconds since 06.Jan.1980 */ - 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", p->if_chain, p->rf_chain, ((double)p->freq_hz / 1e6)); - if (j > 0) { - buff_index += j; - } else { - MSG("ERROR: [up] snprintf failed line %u\n", (__LINE__ - 4)); - exit(EXIT_FAILURE); - } - - /* Packet status, 9-10 useful chars */ - switch (p->status) { - case STAT_CRC_OK: - memcpy((void *)(buff_up + buff_index), (void *)",\"stat\":1", 9); - buff_index += 9; - break; - case STAT_CRC_BAD: - memcpy((void *)(buff_up + buff_index), (void *)",\"stat\":-1", 10); - buff_index += 10; - break; - case STAT_NO_CRC: - memcpy((void *)(buff_up + buff_index), (void *)",\"stat\":0", 9); - buff_index += 9; - break; - default: - MSG("ERROR: [up] received packet with unknown status\n"); - memcpy((void *)(buff_up + buff_index), (void *)",\"stat\":?", 9); - buff_index += 9; - exit(EXIT_FAILURE); - } - - /* Packet modulation, 13-14 useful chars */ - if (p->modulation == MOD_LORA) { - memcpy((void *)(buff_up + buff_index), (void *)",\"modu\":\"LORA\"", 14); - buff_index += 14; - - /* Lora datarate & bandwidth, 16-19 useful chars */ - switch (p->datarate) { - case DR_LORA_SF7: - memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF7", 12); - buff_index += 12; - break; - case DR_LORA_SF8: - memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF8", 12); - buff_index += 12; - break; - case DR_LORA_SF9: - memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF9", 12); - buff_index += 12; - break; - case DR_LORA_SF10: - memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF10", 13); - buff_index += 13; - break; - case DR_LORA_SF11: - memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF11", 13); - buff_index += 13; - break; - case DR_LORA_SF12: - memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF12", 13); - buff_index += 13; - break; - default: - MSG("ERROR: [up] lora packet with unknown datarate\n"); - memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF?", 12); - buff_index += 12; - exit(EXIT_FAILURE); - } - switch (p->bandwidth) { - case BW_125KHZ: - memcpy((void *)(buff_up + buff_index), (void *)"BW125\"", 6); - buff_index += 6; - break; - case BW_250KHZ: - memcpy((void *)(buff_up + buff_index), (void *)"BW250\"", 6); - buff_index += 6; - break; - case BW_500KHZ: - memcpy((void *)(buff_up + buff_index), (void *)"BW500\"", 6); - buff_index += 6; - break; - default: - MSG("ERROR: [up] lora packet with unknown bandwidth\n"); - memcpy((void *)(buff_up + buff_index), (void *)"BW?\"", 4); - buff_index += 4; - exit(EXIT_FAILURE); - } - - /* Packet ECC coding rate, 11-13 useful chars */ - switch (p->coderate) { - case CR_LORA_4_5: - memcpy((void *)(buff_up + buff_index), (void *)",\"codr\":\"4/5\"", 13); - buff_index += 13; - break; - case CR_LORA_4_6: - memcpy((void *)(buff_up + buff_index), (void *)",\"codr\":\"4/6\"", 13); - buff_index += 13; - break; - case CR_LORA_4_7: - memcpy((void *)(buff_up + buff_index), (void *)",\"codr\":\"4/7\"", 13); - buff_index += 13; - break; - case CR_LORA_4_8: - memcpy((void *)(buff_up + buff_index), (void *)",\"codr\":\"4/8\"", 13); - buff_index += 13; - break; - case 0: /* treat the CR0 case (mostly false sync) */ - memcpy((void *)(buff_up + buff_index), (void *)",\"codr\":\"OFF\"", 13); - buff_index += 13; - break; - default: - MSG("ERROR: [up] lora packet with unknown coderate\n"); - memcpy((void *)(buff_up + buff_index), (void *)",\"codr\":\"?\"", 11); - buff_index += 11; - exit(EXIT_FAILURE); - } - - /* Lora SNR, 11-13 useful chars */ - j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, ",\"lsnr\":%.1f", p->snr); - if (j > 0) { - buff_index += j; - } else { - MSG("ERROR: [up] snprintf failed line %u\n", (__LINE__ - 4)); - exit(EXIT_FAILURE); - } - } else if (p->modulation == MOD_FSK) { - memcpy((void *)(buff_up + buff_index), (void *)",\"modu\":\"FSK\"", 13); - buff_index += 13; - - /* FSK datarate, 11-14 useful chars */ - j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, ",\"datr\":%u", p->datarate); - if (j > 0) { - buff_index += j; - } else { - MSG("ERROR: [up] snprintf failed line %u\n", (__LINE__ - 4)); - exit(EXIT_FAILURE); - } - } else { - MSG("ERROR: [up] received packet with unknown modulation\n"); - exit(EXIT_FAILURE); - } - - /* Packet RSSI, payload size, 18-23 useful chars */ - j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, ",\"rssi\":%.0f,\"size\":%u", p->rssi, p->size); - if (j > 0) { - buff_index += j; - } else { - MSG("ERROR: [up] snprintf failed line %u\n", (__LINE__ - 4)); - exit(EXIT_FAILURE); - } - - /* Packet base64-encoded payload, 14-350 useful chars */ - memcpy((void *)(buff_up + buff_index), (void *)",\"data\":\"", 9); - buff_index += 9; - j = bin_to_b64(p->payload, p->size, (char *)(buff_up + buff_index), 341); /* 255 bytes = 340 chars in b64 + null char */ - if (j>=0) { - buff_index += j; - } else { - MSG("ERROR: [up] bin_to_b64 failed line %u\n", (__LINE__ - 5)); - exit(EXIT_FAILURE); - } - buff_up[buff_index] = '"'; - ++buff_index; - - /* End of packet serialization */ - buff_up[buff_index] = '}'; - ++buff_index; - ++pkt_in_dgram; - } - - /* restart fetch sequence without sending empty JSON if all packets have been filtered out */ - if (pkt_in_dgram == 0) { - if (send_report == true) { - /* need to clean up the beginning of the payload */ - buff_index -= 8; /* removes "rxpk":[ */ - } else { - /* all packet have been filtered out and no report, restart loop */ - continue; - } - } else { - /* end of packet array */ - buff_up[buff_index] = ']'; - ++buff_index; - /* add separator if needed */ - if (send_report == true) { - buff_up[buff_index] = ','; - ++buff_index; - } - } - - /* add status report if a new one is available */ - if (send_report == true) { - pthread_mutex_lock(&mx_stat_rep); - report_ready = false; - j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, "%s", status_report); - pthread_mutex_unlock(&mx_stat_rep); - if (j > 0) { - buff_index += j; - } else { - MSG("ERROR: [up] snprintf failed line %u\n", (__LINE__ - 5)); - exit(EXIT_FAILURE); - } - } - - /* end of JSON datagram payload */ - buff_up[buff_index] = '}'; - ++buff_index; - buff_up[buff_index] = 0; /* add string terminator, for safety */ - - printf("\nJSON up: %s\n", (char *)(buff_up + 12)); /* DEBUG: display JSON payload */ - - /* send datagram to server */ - send(sock_up, (void *)buff_up, buff_index, 0); - clock_gettime(CLOCK_MONOTONIC, &send_time); - pthread_mutex_lock(&mx_meas_up); - meas_up_dgram_sent += 1; - meas_up_network_byte += buff_index; - - /* wait for acknowledge (in 2 times, to catch extra packets) */ - for (i=0; i<2; ++i) { - j = recv(sock_up, (void *)buff_ack, sizeof buff_ack, 0); - clock_gettime(CLOCK_MONOTONIC, &recv_time); - if (j == -1) { - if (errno == EAGAIN) { /* timeout */ - continue; - } else { /* server connection error */ - break; - } - } else if ((j < 4) || (buff_ack[0] != PROTOCOL_VERSION) || (buff_ack[3] != PKT_PUSH_ACK)) { - //MSG("WARNING: [up] ignored invalid non-ACL packet\n"); - continue; - } else if ((buff_ack[1] != token_h) || (buff_ack[2] != token_l)) { - //MSG("WARNING: [up] ignored out-of sync ACK packet\n"); - continue; - } else { - MSG("INFO: [up] PUSH_ACK received in %i ms\n", (int)(1000 * difftimespec(recv_time, send_time))); - meas_up_ack_rcv += 1; - break; - } - } - pthread_mutex_unlock(&mx_meas_up); - } - MSG("\nINFO: End of upstream thread\n"); -} - -/* -------------------------------------------------------------------------- */ -/* --- THREAD 2: POLLING SERVER AND ENQUEUING PACKETS IN JIT QUEUE ---------- */ - -void thread_down(void) { - int i; /* loop variables */ - - /* configuration and metadata for an outbound packet */ - struct lgw_pkt_tx_s txpkt; - bool sent_immediate = false; /* option to sent the packet immediately */ - - /* local timekeeping variables */ - struct timespec send_time; /* time of the pull request */ - struct timespec recv_time; /* time of return from recv socket call */ - - /* data buffers */ - uint8_t buff_down[1000]; /* buffer to receive downstream packets */ - uint8_t buff_req[12]; /* buffer to compose pull requests */ - int msg_len; - - /* protocol variables */ - uint8_t token_h; /* random token for acknowledgement matching */ - uint8_t token_l; /* random token for acknowledgement matching */ - bool req_ack = false; /* keep track of whether PULL_DATA was acknowledged or not */ - - /* JSON parsing variables */ - JSON_Value *root_val = NULL; - JSON_Object *txpk_obj = NULL; - JSON_Value *val = NULL; /* needed to detect the absence of some fields */ - const char *str; /* pointer to sub-strings in the JSON data */ - short x0, x1; - uint64_t x2; - double x3, x4; - - /* variables to send on GPS timestamp */ - struct tref local_ref; /* time reference used for GPS <-> timestamp conversion */ - struct timespec gps_tx; /* GPS time that needs to be converted to timestamp */ - - /* beacon variables */ - struct lgw_pkt_tx_s beacon_pkt; - uint8_t beacon_chan; - uint8_t beacon_loop; - size_t beacon_RFU1_size = 0; - size_t beacon_RFU2_size = 0; - uint8_t beacon_pyld_idx = 0; - time_t diff_beacon_time; - struct timespec next_beacon_gps_time; /* gps time of next beacon packet */ - struct timespec last_beacon_gps_time; /* gps time of last enqueued beacon packet */ - int retry; - - /* beacon data fields, byte 0 is Least Significant Byte */ - int32_t field_latitude; /* 3 bytes, derived from reference latitude */ - int32_t field_longitude; /* 3 bytes, derived from reference longitude */ - uint16_t field_crc1, field_crc2; - - /* auto-quit variable */ - uint32_t autoquit_cnt = 0; /* count the number of PULL_DATA sent since the latest PULL_ACK */ - - /* Just In Time downlink */ - struct timeval current_unix_time; - struct timeval current_concentrator_time; - enum jit_error_e jit_result = JIT_ERROR_OK; - enum jit_pkt_type_e downlink_type; - - /* set downstream socket RX timeout */ - i = setsockopt(sock_down, SOL_SOCKET, SO_RCVTIMEO, (void *)&pull_timeout, sizeof pull_timeout); - if (i != 0) { - MSG("ERROR: [down] setsockopt returned %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - - /* pre-fill the pull request buffer with fixed fields */ - buff_req[0] = PROTOCOL_VERSION; - buff_req[3] = PKT_PULL_DATA; - *(uint32_t *)(buff_req + 4) = net_mac_h; - *(uint32_t *)(buff_req + 8) = net_mac_l; - - /* beacon variables initialization */ - last_beacon_gps_time.tv_sec = 0; - last_beacon_gps_time.tv_nsec = 0; - - /* beacon packet parameters */ - beacon_pkt.tx_mode = ON_GPS; /* send on PPS pulse */ - beacon_pkt.rf_chain = 0; /* antenna A */ - beacon_pkt.rf_power = beacon_power; - beacon_pkt.modulation = MOD_LORA; - switch (beacon_bw_hz) { - case 125000: - beacon_pkt.bandwidth = BW_125KHZ; - break; - case 500000: - beacon_pkt.bandwidth = BW_500KHZ; - break; - default: - /* should not happen */ - MSG("ERROR: unsupported bandwidth for beacon\n"); - exit(EXIT_FAILURE); - } - switch (beacon_datarate) { - case 8: - beacon_pkt.datarate = DR_LORA_SF8; - beacon_RFU1_size = 1; - beacon_RFU2_size = 3; - break; - case 9: - beacon_pkt.datarate = DR_LORA_SF9; - beacon_RFU1_size = 2; - beacon_RFU2_size = 0; - break; - case 10: - beacon_pkt.datarate = DR_LORA_SF10; - beacon_RFU1_size = 3; - beacon_RFU2_size = 1; - break; - case 12: - beacon_pkt.datarate = DR_LORA_SF12; - beacon_RFU1_size = 5; - beacon_RFU2_size = 3; - break; - default: - /* should not happen */ - MSG("ERROR: unsupported datarate for beacon\n"); - exit(EXIT_FAILURE); - } - beacon_pkt.size = beacon_RFU1_size + 4 + 2 + 7 + beacon_RFU2_size + 2; - beacon_pkt.coderate = CR_LORA_4_5; - beacon_pkt.invert_pol = false; - beacon_pkt.preamble = 10; - beacon_pkt.no_crc = true; - beacon_pkt.no_header = true; - - /* network common part beacon fields (little endian) */ - for (i = 0; i < (int)beacon_RFU1_size; i++) { - beacon_pkt.payload[beacon_pyld_idx++] = 0x0; - } - - /* network common part beacon fields (little endian) */ - beacon_pyld_idx += 4; /* time (variable), filled later */ - beacon_pyld_idx += 2; /* crc1 (variable), filled later */ - - /* calculate the latitude and longitude that must be publicly reported */ - field_latitude = (int32_t)((reference_coord.lat / 90.0) * (double)(1<<23)); - if (field_latitude > (int32_t)0x007FFFFF) { - field_latitude = (int32_t)0x007FFFFF; /* +90 N is represented as 89.99999 N */ - } else if (field_latitude < (int32_t)0xFF800000) { - field_latitude = (int32_t)0xFF800000; - } - field_longitude = (int32_t)((reference_coord.lon / 180.0) * (double)(1<<23)); - if (field_longitude > (int32_t)0x007FFFFF) { - field_longitude = (int32_t)0x007FFFFF; /* +180 E is represented as 179.99999 E */ - } else if (field_longitude < (int32_t)0xFF800000) { - field_longitude = (int32_t)0xFF800000; - } - - /* gateway specific beacon fields */ - beacon_pkt.payload[beacon_pyld_idx++] = beacon_infodesc; - beacon_pkt.payload[beacon_pyld_idx++] = 0xFF & field_latitude; - beacon_pkt.payload[beacon_pyld_idx++] = 0xFF & (field_latitude >> 8); - beacon_pkt.payload[beacon_pyld_idx++] = 0xFF & (field_latitude >> 16); - beacon_pkt.payload[beacon_pyld_idx++] = 0xFF & field_longitude; - beacon_pkt.payload[beacon_pyld_idx++] = 0xFF & (field_longitude >> 8); - beacon_pkt.payload[beacon_pyld_idx++] = 0xFF & (field_longitude >> 16); - - /* RFU */ - for (i = 0; i < (int)beacon_RFU2_size; i++) { - beacon_pkt.payload[beacon_pyld_idx++] = 0x0; - } - - /* CRC of the beacon gateway specific part fields */ - field_crc2 = crc16((beacon_pkt.payload + 6 + beacon_RFU1_size), 7 + beacon_RFU2_size); - beacon_pkt.payload[beacon_pyld_idx++] = 0xFF & field_crc2; - beacon_pkt.payload[beacon_pyld_idx++] = 0xFF & (field_crc2 >> 8); - - /* JIT queue initialization */ - jit_queue_init(&jit_queue); - - while (!exit_sig && !quit_sig) { - - /* auto-quit if the threshold is crossed */ - if ((autoquit_threshold > 0) && (autoquit_cnt >= autoquit_threshold)) { - exit_sig = true; - MSG("INFO: [down] the last %u PULL_DATA were not ACKed, exiting application\n", autoquit_threshold); - break; - } - - /* generate random token for request */ - token_h = (uint8_t)rand(); /* random token */ - token_l = (uint8_t)rand(); /* random token */ - buff_req[1] = token_h; - buff_req[2] = token_l; - - /* send PULL request and record time */ - send(sock_down, (void *)buff_req, sizeof buff_req, 0); - clock_gettime(CLOCK_MONOTONIC, &send_time); - pthread_mutex_lock(&mx_meas_dw); - meas_dw_pull_sent += 1; - pthread_mutex_unlock(&mx_meas_dw); - req_ack = false; - autoquit_cnt++; - - /* listen to packets and process them until a new PULL request must be sent */ - recv_time = send_time; - while ((int)difftimespec(recv_time, send_time) < keepalive_time) { - - /* try to receive a datagram */ - msg_len = recv(sock_down, (void *)buff_down, (sizeof buff_down)-1, 0); - clock_gettime(CLOCK_MONOTONIC, &recv_time); - - /* Pre-allocate beacon slots in JiT queue, to check downlink collisions */ - beacon_loop = JIT_NUM_BEACON_IN_QUEUE - jit_queue.num_beacon; - retry = 0; - while (beacon_loop && (beacon_period != 0)) { - pthread_mutex_lock(&mx_timeref); - /* Wait for GPS to be ready before inserting beacons in JiT queue */ - if ((gps_ref_valid == true) && (xtal_correct_ok == true)) { - - /* compute GPS time for next beacon to come */ - /* LoRaWAN: T = k*beacon_period + TBeaconDelay */ - /* with TBeaconDelay = [1.5ms +/- 1µs]*/ - if (last_beacon_gps_time.tv_sec == 0) { - /* if no beacon has been queued, get next slot from current GPS time */ - diff_beacon_time = time_reference_gps.gps.tv_sec % ((time_t)beacon_period); - next_beacon_gps_time.tv_sec = time_reference_gps.gps.tv_sec + - ((time_t)beacon_period - diff_beacon_time); - } else { - /* if there is already a beacon, take it as reference */ - next_beacon_gps_time.tv_sec = last_beacon_gps_time.tv_sec + beacon_period; - } - /* now we can add a beacon_period to the reference to get next beacon GPS time */ - next_beacon_gps_time.tv_sec += (retry * beacon_period); - next_beacon_gps_time.tv_nsec = 0; - -#if DEBUG_BEACON - { - time_t time_unix; - - time_unix = time_reference_gps.gps.tv_sec + UNIX_GPS_EPOCH_OFFSET; - MSG_DEBUG(DEBUG_BEACON, "GPS-now : %s", ctime(&time_unix)); - time_unix = last_beacon_gps_time.tv_sec + UNIX_GPS_EPOCH_OFFSET; - MSG_DEBUG(DEBUG_BEACON, "GPS-last: %s", ctime(&time_unix)); - time_unix = next_beacon_gps_time.tv_sec + UNIX_GPS_EPOCH_OFFSET; - MSG_DEBUG(DEBUG_BEACON, "GPS-next: %s", ctime(&time_unix)); - } -#endif - - /* convert GPS time to concentrator time, and set packet counter for JiT trigger */ - lgw_gps2cnt(time_reference_gps, next_beacon_gps_time, &(beacon_pkt.count_us)); - pthread_mutex_unlock(&mx_timeref); - - /* apply frequency correction to beacon TX frequency */ - if (beacon_freq_nb > 1) { - beacon_chan = (next_beacon_gps_time.tv_sec / beacon_period) % beacon_freq_nb; /* floor rounding */ - } else { - beacon_chan = 0; - } - /* Compute beacon frequency */ - beacon_pkt.freq_hz = beacon_freq_hz + (beacon_chan * beacon_freq_step); - - /* load time in beacon payload */ - beacon_pyld_idx = beacon_RFU1_size; - beacon_pkt.payload[beacon_pyld_idx++] = 0xFF & next_beacon_gps_time.tv_sec; - beacon_pkt.payload[beacon_pyld_idx++] = 0xFF & (next_beacon_gps_time.tv_sec >> 8); - beacon_pkt.payload[beacon_pyld_idx++] = 0xFF & (next_beacon_gps_time.tv_sec >> 16); - beacon_pkt.payload[beacon_pyld_idx++] = 0xFF & (next_beacon_gps_time.tv_sec >> 24); - - /* calculate CRC */ - field_crc1 = crc16(beacon_pkt.payload, 4 + beacon_RFU1_size); /* CRC for the network common part */ - beacon_pkt.payload[beacon_pyld_idx++] = 0xFF & field_crc1; - beacon_pkt.payload[beacon_pyld_idx++] = 0xFF & (field_crc1 >> 8); - - /* Insert beacon packet in JiT queue */ - gettimeofday(¤t_unix_time, NULL); - get_concentrator_time(¤t_concentrator_time, current_unix_time); - jit_result = jit_enqueue(&jit_queue, ¤t_concentrator_time, &beacon_pkt, JIT_PKT_TYPE_BEACON); - if (jit_result == JIT_ERROR_OK) { - /* update stats */ - pthread_mutex_lock(&mx_meas_dw); - meas_nb_beacon_queued += 1; - pthread_mutex_unlock(&mx_meas_dw); - - /* One more beacon in the queue */ - beacon_loop--; - retry = 0; - last_beacon_gps_time.tv_sec = next_beacon_gps_time.tv_sec; /* keep this beacon time as reference for next one to be programmed */ - - /* display beacon payload */ - MSG("INFO: Beacon queued (count_us=%u, freq_hz=%u, size=%u):\n", beacon_pkt.count_us, beacon_pkt.freq_hz, beacon_pkt.size); - printf( " => " ); - for (i = 0; i < beacon_pkt.size; ++i) { - MSG("%02X ", beacon_pkt.payload[i]); - } - MSG("\n"); - } else { - MSG_DEBUG(DEBUG_BEACON, "--> beacon queuing failed with %d\n", jit_result); - /* update stats */ - pthread_mutex_lock(&mx_meas_dw); - if (jit_result != JIT_ERROR_COLLISION_BEACON) { - meas_nb_beacon_rejected += 1; - } - pthread_mutex_unlock(&mx_meas_dw); - /* In case previous enqueue failed, we retry one period later until it succeeds */ - /* Note: In case the GPS has been unlocked for a while, there can be lots of retries */ - /* to be done from last beacon time to a new valid one */ - retry++; - MSG_DEBUG(DEBUG_BEACON, "--> beacon queuing retry=%d\n", retry); - } - } else { - pthread_mutex_unlock(&mx_timeref); - break; - } - } - - /* if no network message was received, got back to listening sock_down socket */ - if (msg_len == -1) { - //MSG("WARNING: [down] recv returned %s\n", strerror(errno)); /* too verbose */ - continue; - } - - /* if the datagram does not respect protocol, just ignore it */ - if ((msg_len < 4) || (buff_down[0] != PROTOCOL_VERSION) || ((buff_down[3] != PKT_PULL_RESP) && (buff_down[3] != PKT_PULL_ACK))) { - MSG("WARNING: [down] ignoring invalid packet len=%d, protocol_version=%d, id=%d\n", - msg_len, buff_down[0], buff_down[3]); - continue; - } - - /* if the datagram is an ACK, check token */ - if (buff_down[3] == PKT_PULL_ACK) { - if ((buff_down[1] == token_h) && (buff_down[2] == token_l)) { - if (req_ack) { - MSG("INFO: [down] duplicate ACK received :)\n"); - } else { /* if that packet was not already acknowledged */ - req_ack = true; - autoquit_cnt = 0; - pthread_mutex_lock(&mx_meas_dw); - meas_dw_ack_rcv += 1; - pthread_mutex_unlock(&mx_meas_dw); - MSG("INFO: [down] PULL_ACK received in %i ms\n", (int)(1000 * difftimespec(recv_time, send_time))); - } - } else { /* out-of-sync token */ - MSG("INFO: [down] received out-of-sync ACK\n"); - } - continue; - } - - /* the datagram is a PULL_RESP */ - buff_down[msg_len] = 0; /* add string terminator, just to be safe */ - MSG("INFO: [down] PULL_RESP received - token[%d:%d] :)\n", buff_down[1], buff_down[2]); /* very verbose */ - printf("\nJSON down: %s\n", (char *)(buff_down + 4)); /* DEBUG: display JSON payload */ - - /* initialize TX struct and try to parse JSON */ - memset(&txpkt, 0, sizeof txpkt); - root_val = json_parse_string_with_comments((const char *)(buff_down + 4)); /* JSON offset */ - if (root_val == NULL) { - MSG("WARNING: [down] invalid JSON, TX aborted\n"); - continue; - } - - /* look for JSON sub-object 'txpk' */ - txpk_obj = json_object_get_object(json_value_get_object(root_val), "txpk"); - if (txpk_obj == NULL) { - MSG("WARNING: [down] no \"txpk\" object in JSON, TX aborted\n"); - json_value_free(root_val); - continue; - } - - /* Parse "immediate" tag, or target timestamp, or UTC time to be converted by GPS (mandatory) */ - i = json_object_get_boolean(txpk_obj,"imme"); /* can be 1 if true, 0 if false, or -1 if not a JSON boolean */ - if (i == 1) { - /* TX procedure: send immediately */ - sent_immediate = true; - downlink_type = JIT_PKT_TYPE_DOWNLINK_CLASS_C; - MSG("INFO: [down] a packet will be sent in \"immediate\" mode\n"); - } else { - sent_immediate = false; - val = json_object_get_value(txpk_obj,"tmst"); - if (val != NULL) { - /* TX procedure: send on timestamp value */ - txpkt.count_us = (uint32_t)json_value_get_number(val); - - /* Concentrator timestamp is given, we consider it is a Class A downlink */ - downlink_type = JIT_PKT_TYPE_DOWNLINK_CLASS_A; - } else { - /* TX procedure: send on GPS time (converted to timestamp value) */ - val = json_object_get_value(txpk_obj, "tmms"); - if (val == NULL) { - MSG("WARNING: [down] no mandatory \"txpk.tmst\" or \"txpk.tmms\" objects in JSON, TX aborted\n"); - json_value_free(root_val); - continue; - } - if (gps_enabled == true) { - pthread_mutex_lock(&mx_timeref); - if (gps_ref_valid == true) { - local_ref = time_reference_gps; - pthread_mutex_unlock(&mx_timeref); - } else { - pthread_mutex_unlock(&mx_timeref); - MSG("WARNING: [down] no valid GPS time reference yet, impossible to send packet on specific GPS time, TX aborted\n"); - json_value_free(root_val); - - /* send acknoledge datagram to server */ - send_tx_ack(buff_down[1], buff_down[2], JIT_ERROR_GPS_UNLOCKED); - continue; - } - } else { - MSG("WARNING: [down] GPS disabled, impossible to send packet on specific GPS time, TX aborted\n"); - json_value_free(root_val); - - /* send acknoledge datagram to server */ - send_tx_ack(buff_down[1], buff_down[2], JIT_ERROR_GPS_UNLOCKED); - continue; - } - - /* Get GPS time from JSON */ - x2 = (uint64_t)json_value_get_number(val); - - /* Convert GPS time from milliseconds to timespec */ - x3 = modf((double)x2/1E3, &x4); - gps_tx.tv_sec = (time_t)x4; /* get seconds from integer part */ - gps_tx.tv_nsec = (long)(x3 * 1E9); /* get nanoseconds from fractional part */ - - /* transform GPS time to timestamp */ - i = lgw_gps2cnt(local_ref, gps_tx, &(txpkt.count_us)); - if (i != LGW_GPS_SUCCESS) { - MSG("WARNING: [down] could not convert GPS time to timestamp, TX aborted\n"); - json_value_free(root_val); - continue; - } else { - MSG("INFO: [down] a packet will be sent on timestamp value %u (calculated from GPS time)\n", txpkt.count_us); - } - - /* GPS timestamp is given, we consider it is a Class B downlink */ - downlink_type = JIT_PKT_TYPE_DOWNLINK_CLASS_B; - } - } - - /* Parse "No CRC" flag (optional field) */ - val = json_object_get_value(txpk_obj,"ncrc"); - if (val != NULL) { - txpkt.no_crc = (bool)json_value_get_boolean(val); - } - - /* parse target frequency (mandatory) */ - val = json_object_get_value(txpk_obj,"freq"); - if (val == NULL) { - MSG("WARNING: [down] no mandatory \"txpk.freq\" object in JSON, TX aborted\n"); - json_value_free(root_val); - continue; - } - txpkt.freq_hz = (uint32_t)((double)(1.0e6) * json_value_get_number(val)); - - /* parse RF chain used for TX (mandatory) */ - val = json_object_get_value(txpk_obj,"rfch"); - if (val == NULL) { - MSG("WARNING: [down] no mandatory \"txpk.rfch\" object in JSON, TX aborted\n"); - json_value_free(root_val); - continue; - } - txpkt.rf_chain = (uint8_t)json_value_get_number(val); - - /* parse TX power (optional field) */ - val = json_object_get_value(txpk_obj,"powe"); - if (val != NULL) { - txpkt.rf_power = (int8_t)json_value_get_number(val) - antenna_gain; - } - - /* Parse modulation (mandatory) */ - str = json_object_get_string(txpk_obj, "modu"); - if (str == NULL) { - MSG("WARNING: [down] no mandatory \"txpk.modu\" object in JSON, TX aborted\n"); - json_value_free(root_val); - continue; - } - if (strcmp(str, "LORA") == 0) { - /* Lora modulation */ - txpkt.modulation = MOD_LORA; - - /* Parse Lora spreading-factor and modulation bandwidth (mandatory) */ - str = json_object_get_string(txpk_obj, "datr"); - if (str == NULL) { - MSG("WARNING: [down] no mandatory \"txpk.datr\" object in JSON, TX aborted\n"); - json_value_free(root_val); - continue; - } - i = sscanf(str, "SF%2hdBW%3hd", &x0, &x1); - if (i != 2) { - MSG("WARNING: [down] format error in \"txpk.datr\", TX aborted\n"); - json_value_free(root_val); - continue; - } - switch (x0) { - case 7: txpkt.datarate = DR_LORA_SF7; break; - case 8: txpkt.datarate = DR_LORA_SF8; break; - case 9: txpkt.datarate = DR_LORA_SF9; break; - case 10: txpkt.datarate = DR_LORA_SF10; break; - case 11: txpkt.datarate = DR_LORA_SF11; break; - case 12: txpkt.datarate = DR_LORA_SF12; break; - default: - MSG("WARNING: [down] format error in \"txpk.datr\", invalid SF, TX aborted\n"); - json_value_free(root_val); - continue; - } - switch (x1) { - case 125: txpkt.bandwidth = BW_125KHZ; break; - case 250: txpkt.bandwidth = BW_250KHZ; break; - case 500: txpkt.bandwidth = BW_500KHZ; break; - default: - MSG("WARNING: [down] format error in \"txpk.datr\", invalid BW, TX aborted\n"); - json_value_free(root_val); - continue; - } - - /* Parse ECC coding rate (optional field) */ - str = json_object_get_string(txpk_obj, "codr"); - if (str == NULL) { - MSG("WARNING: [down] no mandatory \"txpk.codr\" object in json, TX aborted\n"); - json_value_free(root_val); - continue; - } - if (strcmp(str, "4/5") == 0) txpkt.coderate = CR_LORA_4_5; - else if (strcmp(str, "4/6") == 0) txpkt.coderate = CR_LORA_4_6; - else if (strcmp(str, "2/3") == 0) txpkt.coderate = CR_LORA_4_6; - else if (strcmp(str, "4/7") == 0) txpkt.coderate = CR_LORA_4_7; - else if (strcmp(str, "4/8") == 0) txpkt.coderate = CR_LORA_4_8; - else if (strcmp(str, "1/2") == 0) txpkt.coderate = CR_LORA_4_8; - else { - MSG("WARNING: [down] format error in \"txpk.codr\", TX aborted\n"); - json_value_free(root_val); - continue; - } - - /* Parse signal polarity switch (optional field) */ - val = json_object_get_value(txpk_obj,"ipol"); - if (val != NULL) { - txpkt.invert_pol = (bool)json_value_get_boolean(val); - } - - /* parse Lora preamble length (optional field, optimum min value enforced) */ - val = json_object_get_value(txpk_obj,"prea"); - if (val != NULL) { - i = (int)json_value_get_number(val); - if (i >= MIN_LORA_PREAMB) { - txpkt.preamble = (uint16_t)i; - } else { - txpkt.preamble = (uint16_t)MIN_LORA_PREAMB; - } - } else { - txpkt.preamble = (uint16_t)STD_LORA_PREAMB; - } - - } else if (strcmp(str, "FSK") == 0) { - /* FSK modulation */ - txpkt.modulation = MOD_FSK; - - /* parse FSK bitrate (mandatory) */ - val = json_object_get_value(txpk_obj,"datr"); - if (val == NULL) { - MSG("WARNING: [down] no mandatory \"txpk.datr\" object in JSON, TX aborted\n"); - json_value_free(root_val); - continue; - } - txpkt.datarate = (uint32_t)(json_value_get_number(val)); - - /* parse frequency deviation (mandatory) */ - val = json_object_get_value(txpk_obj,"fdev"); - if (val == NULL) { - MSG("WARNING: [down] no mandatory \"txpk.fdev\" object in JSON, TX aborted\n"); - json_value_free(root_val); - continue; - } - txpkt.f_dev = (uint8_t)(json_value_get_number(val) / 1000.0); /* JSON value in Hz, txpkt.f_dev in kHz */ - - /* parse FSK preamble length (optional field, optimum min value enforced) */ - val = json_object_get_value(txpk_obj,"prea"); - if (val != NULL) { - i = (int)json_value_get_number(val); - if (i >= MIN_FSK_PREAMB) { - txpkt.preamble = (uint16_t)i; - } else { - txpkt.preamble = (uint16_t)MIN_FSK_PREAMB; - } - } else { - txpkt.preamble = (uint16_t)STD_FSK_PREAMB; - } - - } else { - MSG("WARNING: [down] invalid modulation in \"txpk.modu\", TX aborted\n"); - json_value_free(root_val); - continue; - } - - /* Parse payload length (mandatory) */ - val = json_object_get_value(txpk_obj,"size"); - if (val == NULL) { - MSG("WARNING: [down] no mandatory \"txpk.size\" object in JSON, TX aborted\n"); - json_value_free(root_val); - continue; - } - txpkt.size = (uint16_t)json_value_get_number(val); - - /* Parse payload data (mandatory) */ - str = json_object_get_string(txpk_obj, "data"); - if (str == NULL) { - MSG("WARNING: [down] no mandatory \"txpk.data\" object in JSON, TX aborted\n"); - json_value_free(root_val); - continue; - } - i = b64_to_bin(str, strlen(str), txpkt.payload, sizeof txpkt.payload); - if (i != txpkt.size) { - MSG("WARNING: [down] mismatch between .size and .data size once converter to binary\n"); - } - - /* free the JSON parse tree from memory */ - json_value_free(root_val); - - /* select TX mode */ - if (sent_immediate) { - txpkt.tx_mode = IMMEDIATE; - } else { - txpkt.tx_mode = TIMESTAMPED; - } - - /* record measurement data */ - pthread_mutex_lock(&mx_meas_dw); - meas_dw_dgram_rcv += 1; /* count only datagrams with no JSON errors */ - meas_dw_network_byte += msg_len; /* meas_dw_network_byte */ - meas_dw_payload_byte += txpkt.size; - pthread_mutex_unlock(&mx_meas_dw); - - /* check TX parameter before trying to queue packet */ - jit_result = JIT_ERROR_OK; - if ((txpkt.freq_hz < tx_freq_min[txpkt.rf_chain]) || (txpkt.freq_hz > tx_freq_max[txpkt.rf_chain])) { - jit_result = JIT_ERROR_TX_FREQ; - MSG("ERROR: Packet REJECTED, unsupported frequency - %u (min:%u,max:%u)\n", txpkt.freq_hz, tx_freq_min[txpkt.rf_chain], tx_freq_max[txpkt.rf_chain]); - } - if (jit_result == JIT_ERROR_OK) { - for (i=0; i txpkt.rf_power) { - if (0 != i) - { - MSG("INFO: >= used txlut index:%d. __1\n", i - 1); - MSG("WARNING: network-server wants to use powe = %d, and actually uses powd = %d\n", txpkt.rf_power, txlut.lut[i - 1].rf_power); - txpkt.rf_power = txlut.lut[i - 1].rf_power; - } - else - { - MSG("INFO: >= used txlut index:%d. __2\n", i); - MSG("WARNING: network-server wants to use powe = %d, and actually uses powd = %d\n", txpkt.rf_power, txlut.lut[0].rf_power); - txpkt.rf_power = txlut.lut[0].rf_power; - } - break; - } - } - if (i == txlut.size) { - /* Exceeding maximum power, use maximum power */ - MSG("WARNING: power for TX - %d exceeding maximum power - %d, use maximum power - %d\n", txpkt.rf_power, txlut.lut[txlut.size - 1].rf_power, txlut.lut[txlut.size - 1].rf_power); - txpkt.rf_power = txlut.lut[txlut.size - 1].rf_power; - MSG("INFO: >= used txlut index:%d. __3\n", txlut.size - 1); - } - } - - /* insert packet to be sent into JIT queue */ - if (jit_result == JIT_ERROR_OK) { - gettimeofday(¤t_unix_time, NULL); - get_concentrator_time(¤t_concentrator_time, current_unix_time); - jit_result = jit_enqueue(&jit_queue, ¤t_concentrator_time, &txpkt, downlink_type); - if (jit_result != JIT_ERROR_OK) { - printf("ERROR: Packet REJECTED (jit error=%d)\n", jit_result); - } - pthread_mutex_lock(&mx_meas_dw); - meas_nb_tx_requested += 1; - pthread_mutex_unlock(&mx_meas_dw); - } - - /* Send acknoledge datagram to server */ - send_tx_ack(buff_down[1], buff_down[2], jit_result); - } - } - MSG("\nINFO: End of downstream thread\n"); -} - -void print_tx_status(uint8_t tx_status) { - switch (tx_status) { - case TX_OFF: - MSG("INFO: [jit] lgw_status returned TX_OFF\n"); - break; - case TX_FREE: - MSG("INFO: [jit] lgw_status returned TX_FREE\n"); - break; - case TX_EMITTING: - MSG("INFO: [jit] lgw_status returned TX_EMITTING\n"); - break; - case TX_SCHEDULED: - MSG("INFO: [jit] lgw_status returned TX_SCHEDULED\n"); - break; - default: - MSG("INFO: [jit] lgw_status returned UNKNOWN (%d)\n", tx_status); - break; - } -} - - -/* -------------------------------------------------------------------------- */ -/* --- THREAD 3: CHECKING PACKETS TO BE SENT FROM JIT QUEUE AND SEND THEM --- */ - -void thread_jit(void) { - int result = LGW_HAL_SUCCESS; - struct lgw_pkt_tx_s pkt; - int pkt_index = -1; - struct timeval current_unix_time; - struct timeval current_concentrator_time; - enum jit_error_e jit_result; - enum jit_pkt_type_e pkt_type; - uint8_t tx_status; - - while (!exit_sig && !quit_sig) { - wait_ms(10); - - /* transfer data and metadata to the concentrator, and schedule TX */ - gettimeofday(¤t_unix_time, NULL); - get_concentrator_time(¤t_concentrator_time, current_unix_time); - jit_result = jit_peek(&jit_queue, ¤t_concentrator_time, &pkt_index); - if (jit_result == JIT_ERROR_OK) { - if (pkt_index > -1) { - jit_result = jit_dequeue(&jit_queue, pkt_index, &pkt, &pkt_type); - if (jit_result == JIT_ERROR_OK) { - /* update beacon stats */ - if (pkt_type == JIT_PKT_TYPE_BEACON) { - /* Compensate breacon frequency with xtal error */ - pthread_mutex_lock(&mx_xcorr); - pkt.freq_hz = (uint32_t)(xtal_correct * (double)pkt.freq_hz); - MSG_DEBUG(DEBUG_BEACON, "beacon_pkt.freq_hz=%u (xtal_correct=%.15lf)\n", pkt.freq_hz, xtal_correct); - pthread_mutex_unlock(&mx_xcorr); - - /* Update statistics */ - pthread_mutex_lock(&mx_meas_dw); - meas_nb_beacon_sent += 1; - pthread_mutex_unlock(&mx_meas_dw); - MSG("INFO: Beacon dequeued (count_us=%u)\n", pkt.count_us); - } - - /* check if concentrator is free for sending new packet */ - pthread_mutex_lock(&mx_concent); /* may have to wait for a fetch to finish */ - result = lgw_status(TX_STATUS, &tx_status); - pthread_mutex_unlock(&mx_concent); /* free concentrator ASAP */ - if (result == LGW_HAL_ERROR) { - MSG("WARNING: [jit] lgw_status failed\n"); - } else { - if (tx_status == TX_EMITTING) { - MSG("ERROR: concentrator is currently emitting\n"); - print_tx_status(tx_status); - continue; - } else if (tx_status == TX_SCHEDULED) { - MSG("WARNING: a downlink was already scheduled, overwritting it...\n"); - print_tx_status(tx_status); - } else { - /* Nothing to do */ - } - } - - /* send packet to concentrator */ - pthread_mutex_lock(&mx_concent); /* may have to wait for a fetch to finish */ - result = lgw_send(pkt); - pthread_mutex_unlock(&mx_concent); /* free concentrator ASAP */ - if (result == LGW_HAL_ERROR) { - pthread_mutex_lock(&mx_meas_dw); - meas_nb_tx_fail += 1; - pthread_mutex_unlock(&mx_meas_dw); - MSG("WARNING: [jit] lgw_send failed\n"); - continue; - } else { - pthread_mutex_lock(&mx_meas_dw); - meas_nb_tx_ok += 1; - pthread_mutex_unlock(&mx_meas_dw); - MSG_DEBUG(DEBUG_PKT_FWD, "lgw_send done: count_us=%u\n", pkt.count_us); - } - } else { - MSG("ERROR: jit_dequeue failed with %d\n", jit_result); - } - } - } else if (jit_result == JIT_ERROR_EMPTY) { - /* Do nothing, it can happen */ - } else { - MSG("ERROR: jit_peek failed with %d\n", jit_result); - } - } -} - -static void modify_os_time(const uint32_t ppm_tstamp) -{ - struct timespec y; - struct timespec tv; - static bool time_already_set = false; - struct timeval stamp; - gettimeofday(&stamp, NULL); - int time_diff = 0; - lgw_cnt2utc(time_reference_gps, ppm_tstamp, &y); - if ((!gps_enabled) || time_already_set) - { - return; - } - if (y.tv_sec < 1583402711) // time less than '2020-03-05 18:00:00' - { - return; - } - - MSG("INFO: [modify_os_time] local_time=%ld, gps_time=%ld\n", stamp.tv_sec, y.tv_sec); - time_diff = abs(y.tv_sec - stamp.tv_sec); - - if (time_diff < 10) - { - time_already_set = true; - MSG("INFO: [modify_os_time] The difference between the system time(%ld) and the GPS time(%ld) is less than 10 seconds. Use the system time.\n", stamp.tv_sec, y.tv_sec); - return; - } - - tv.tv_sec = y.tv_sec; - tv.tv_nsec = 0; - - int ret = clock_settime(CLOCK_REALTIME, &tv); - if (0 == ret) - { - time_already_set = true; - time_t t; - struct tm* local; - char buf[128] = {0}; - t = time(NULL); - local = localtime(&t); - strftime(buf, 64, "%Y-%m-%d %H:%M:%S", local); - MSG("INFO: [modify_os_time] System time has been synchronized via GPS, %s\n", buf); - } -} - - -/* -------------------------------------------------------------------------- */ -/* --- THREAD 4: PARSE GPS MESSAGE AND KEEP GATEWAY IN SYNC ----------------- */ - -static void gps_process_sync(void) { - struct timespec gps_time; - struct timespec utc; - uint32_t trig_tstamp; /* concentrator timestamp associated with PPM pulse */ - int i = lgw_gps_get(&utc, &gps_time, NULL, NULL); - - /* get GPS time for synchronization */ - if (i != LGW_GPS_SUCCESS) { - MSG("WARNING: [gps] could not get GPS time from GPS\n"); - return; - } - - /* get timestamp captured on PPM pulse */ - pthread_mutex_lock(&mx_concent); - i = lgw_get_trigcnt(&trig_tstamp); - pthread_mutex_unlock(&mx_concent); - if (i != LGW_HAL_SUCCESS) { - MSG("WARNING: [gps] failed to read concentrator timestamp\n"); - return; - } - - /* try to update time reference with the new GPS time & timestamp */ - pthread_mutex_lock(&mx_timeref); - i = lgw_gps_sync(&time_reference_gps, trig_tstamp, utc, gps_time); - modify_os_time(trig_tstamp); - pthread_mutex_unlock(&mx_timeref); - if (i != LGW_GPS_SUCCESS) { - MSG("WARNING: [gps] GPS out of sync, keeping previous time reference\n"); - } -} - -static void gps_process_coords(void) { - /* position variable */ - struct coord_s coord; - struct coord_s gpserr; - int i = lgw_gps_get(NULL, NULL, &coord, &gpserr); - - /* update gateway coordinates */ - pthread_mutex_lock(&mx_meas_gps); - if (i == LGW_GPS_SUCCESS) { - gps_coord_valid = true; - meas_gps_coord = coord; - meas_gps_err = gpserr; - // TODO: report other GPS statistics (typ. signal quality & integrity) - } else { - gps_coord_valid = false; - } - pthread_mutex_unlock(&mx_meas_gps); -} - -void thread_gps(void) { - /* serial variables */ - char serial_buff[128]; /* buffer to receive GPS data */ - size_t wr_idx = 0; /* pointer to end of chars in buffer */ - - /* variables for PPM pulse GPS synchronization */ - enum gps_msg latest_msg; /* keep track of latest NMEA message parsed */ - - /* initialize some variables before loop */ - memset(serial_buff, 0, sizeof serial_buff); - - int invalid_nb_char_count = 0; - while (!exit_sig && !quit_sig) { - size_t rd_idx = 0; - size_t frame_end_idx = 0; - - /* blocking non-canonical read on serial port */ - ssize_t nb_char = read(gps_tty_fd, serial_buff + wr_idx, LGW_GPS_MIN_MSG_SIZE); - if (nb_char <= 0) { - invalid_nb_char_count++; - if ((invalid_nb_char_count % 20000) == 0){ - MSG("WARNING: [gps] read() returned value %d\n", nb_char); - } - continue; - } - wr_idx += (size_t)nb_char; - - /******************************************* - * Scan buffer for UBX/NMEA sync chars and * - * attempt to decode frame if one is found * - *******************************************/ - while(rd_idx < wr_idx) { - size_t frame_size = 0; - - /* Scan buffer for UBX sync char */ - if(serial_buff[rd_idx] == (char)LGW_GPS_UBX_SYNC_CHAR) { - - /*********************** - * Found UBX sync char * - ***********************/ - latest_msg = lgw_parse_ubx(&serial_buff[rd_idx], (wr_idx - rd_idx), &frame_size); - - if (frame_size > 0) { - if (latest_msg == INCOMPLETE) { - /* UBX header found but frame appears to be missing bytes */ - frame_size = 0; - } else if (latest_msg == INVALID) { - /* message header received but message appears to be corrupted */ - MSG("WARNING: [gps] could not get a valid message from GPS (no time)\n"); - frame_size = 0; - } else if (latest_msg == UBX_NAV_TIMEGPS) { - gps_process_sync(); - } - } - } else if(serial_buff[rd_idx] == LGW_GPS_NMEA_SYNC_CHAR) { - /************************ - * Found NMEA sync char * - ************************/ - /* scan for NMEA end marker (LF = 0x0a) */ - char* nmea_end_ptr = memchr(&serial_buff[rd_idx],(int)0x0a, (wr_idx - rd_idx)); - - if(nmea_end_ptr) { - /* found end marker */ - frame_size = nmea_end_ptr - &serial_buff[rd_idx] + 1; - latest_msg = lgw_parse_nmea(&serial_buff[rd_idx], frame_size); - - if(latest_msg == INVALID || latest_msg == UNKNOWN) { - /* checksum failed */ - frame_size = 0; - } else if (latest_msg == NMEA_RMC) { /* Get location from RMC frames */ - gps_process_coords(); - } - } - } - - if(frame_size > 0) { - /* At this point message is a checksum verified frame - we're processed or ignored. Remove frame from buffer */ - rd_idx += frame_size; - frame_end_idx = rd_idx; - } else { - rd_idx++; - } - } /* ...for(rd_idx = 0... */ - - if(frame_end_idx) { - /* Frames have been processed. Remove bytes to end of last processed frame */ - memcpy(serial_buff, &serial_buff[frame_end_idx], wr_idx - frame_end_idx); - wr_idx -= frame_end_idx; - } /* ...for(rd_idx = 0... */ - - /* Prevent buffer overflow */ - if((sizeof(serial_buff) - wr_idx) < LGW_GPS_MIN_MSG_SIZE) { - memcpy(serial_buff, &serial_buff[LGW_GPS_MIN_MSG_SIZE], wr_idx - LGW_GPS_MIN_MSG_SIZE); - wr_idx -= LGW_GPS_MIN_MSG_SIZE; - } - } - MSG("\nINFO: End of GPS thread\n"); -} - -/* -------------------------------------------------------------------------- */ -/* --- THREAD 5: CHECK TIME REFERENCE AND CALCULATE XTAL CORRECTION --------- */ - -void thread_valid(void) { - - /* GPS reference validation variables */ - long gps_ref_age = 0; - bool ref_valid_local = false; - double xtal_err_cpy; - - /* variables for XTAL correction averaging */ - unsigned init_cpt = 0; - double init_acc = 0.0; - double x; - - /* correction debug */ - // FILE * log_file = NULL; - // time_t now_time; - // char log_name[64]; - - /* initialization */ - // time(&now_time); - // strftime(log_name,sizeof log_name,"xtal_err_%Y%m%dT%H%M%SZ.csv",localtime(&now_time)); - // log_file = fopen(log_name, "w"); - // setbuf(log_file, NULL); - // fprintf(log_file,"\"xtal_correct\",\"XERR_INIT_AVG %u XERR_FILT_COEF %u\"\n", XERR_INIT_AVG, XERR_FILT_COEF); // DEBUG - - /* main loop task */ - while (!exit_sig && !quit_sig) { - wait_ms(1000); - - /* calculate when the time reference was last updated */ - pthread_mutex_lock(&mx_timeref); - gps_ref_age = (long)difftime(time(NULL), time_reference_gps.systime); - if ((gps_ref_age >= 0) && (gps_ref_age <= GPS_REF_MAX_AGE)) { - /* time ref is ok, validate and */ - gps_ref_valid = true; - ref_valid_local = true; - xtal_err_cpy = time_reference_gps.xtal_err; - //printf("XTAL err: %.15lf (1/XTAL_err:%.15lf)\n", xtal_err_cpy, 1/xtal_err_cpy); // DEBUG - } else { - /* time ref is too old, invalidate */ - gps_ref_valid = false; - ref_valid_local = false; - } - pthread_mutex_unlock(&mx_timeref); - - /* manage XTAL correction */ - if (ref_valid_local == false) { - /* couldn't sync, or sync too old -> invalidate XTAL correction */ - pthread_mutex_lock(&mx_xcorr); - xtal_correct_ok = false; - xtal_correct = 1.0; - pthread_mutex_unlock(&mx_xcorr); - init_cpt = 0; - init_acc = 0.0; - } else { - if (init_cpt < XERR_INIT_AVG) { - /* initial accumulation */ - init_acc += xtal_err_cpy; - ++init_cpt; - } else if (init_cpt == XERR_INIT_AVG) { - /* initial average calculation */ - pthread_mutex_lock(&mx_xcorr); - xtal_correct = (double)(XERR_INIT_AVG) / init_acc; - //printf("XERR_INIT_AVG=%d, init_acc=%.15lf\n", XERR_INIT_AVG, init_acc); - xtal_correct_ok = true; - pthread_mutex_unlock(&mx_xcorr); - ++init_cpt; - // fprintf(log_file,"%.18lf,\"average\"\n", xtal_correct); // DEBUG - } else { - /* tracking with low-pass filter */ - x = 1 / xtal_err_cpy; - pthread_mutex_lock(&mx_xcorr); - xtal_correct = xtal_correct - xtal_correct/XERR_FILT_COEF + x/XERR_FILT_COEF; - pthread_mutex_unlock(&mx_xcorr); - // 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 - } - MSG("\nINFO: End of validation thread\n"); -} - -/* --- EOF ------------------------------------------------------------------ */ diff --git a/lora/rak2245/loragw_spi.native.c b/lora/rak2245/loragw_spi.native.c deleted file mode 100644 index a4f4b01..0000000 --- a/lora/rak2245/loragw_spi.native.c +++ /dev/null @@ -1,385 +0,0 @@ -/* - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ - \____ \| ___ | (_ _) ___ |/ ___) _ \ - _____) ) ____| | | || |_| ____( (___| | | | -(______/|_____)_|_|_| \__)_____)\____)_| |_| - (C)2013 Semtech-Cycleo - -Description: - Host specific functions to address the LoRa concentrator registers through - a SPI interface. - Single-byte read/write and burst read/write. - Does not handle pagination. - Could be used with multiple SPI ports in parallel (explicit file descriptor) - -License: Revised BSD License, see LICENSE.TXT file include in the project -Maintainer: Sylvain Miermont -*/ - - -/* -------------------------------------------------------------------------- */ -/* --- DEPENDANCIES --------------------------------------------------------- */ - -#include /* C99 types */ -#include /* printf fprintf */ -#include /* malloc free */ -#include /* lseek, close */ -#include /* open */ -#include /* memset */ - -#include -#include - -#include "loragw_spi.h" -#include "loragw_hal.h" - -/* -------------------------------------------------------------------------- */ -/* --- PRIVATE MACROS ------------------------------------------------------- */ - -#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -#if DEBUG_SPI == 1 - #define DEBUG_MSG(str) fprintf(stderr, str) - #define DEBUG_PRINTF(fmt, args...) fprintf(stderr,"%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_SPI_ERROR;} -#else - #define DEBUG_MSG(str) - #define DEBUG_PRINTF(fmt, args...) - #define CHECK_NULL(a) if(a==NULL){return LGW_SPI_ERROR;} -#endif - -/* -------------------------------------------------------------------------- */ -/* --- PRIVATE CONSTANTS ---------------------------------------------------- */ - -#define READ_ACCESS 0x00 -#define WRITE_ACCESS 0x80 -#define SPI_SPEED 2000000 -#define SPI_DEV_PATH "/dev/spidev0.0" -//#define SPI_DEV_PATH "/dev/spidev32766.0" - -/* -------------------------------------------------------------------------- */ -/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */ - -/* SPI initialization and configuration */ -int lgw_spi_open(void **spi_target_ptr) { - int *spi_device = NULL; - int dev; - int a=0, b=0; - int i; - - /* check input variables */ - CHECK_NULL(spi_target_ptr); /* cannot be null, must point on a void pointer (*spi_target_ptr can be null) */ - - /* allocate memory for the device descriptor */ - spi_device = malloc(sizeof(int)); - if (spi_device == NULL) { - DEBUG_MSG("ERROR: MALLOC FAIL\n"); - return LGW_SPI_ERROR; - } - - /* open SPI device */ - dev = open(SPI_DEV_PATH, O_RDWR); - if (dev < 0) { - DEBUG_PRINTF("ERROR: failed to open SPI device %s\n", SPI_DEV_PATH); - return LGW_SPI_ERROR; - } - - /* setting SPI mode to 'mode 0' */ - i = SPI_MODE_0; - a = ioctl(dev, SPI_IOC_WR_MODE, &i); - b = ioctl(dev, SPI_IOC_RD_MODE, &i); - if ((a < 0) || (b < 0)) { - DEBUG_MSG("ERROR: SPI PORT FAIL TO SET IN MODE 0\n"); - close(dev); - free(spi_device); - return LGW_SPI_ERROR; - } - - /* setting SPI max clk (in Hz) */ - i = SPI_SPEED; - a = ioctl(dev, SPI_IOC_WR_MAX_SPEED_HZ, &i); - b = ioctl(dev, SPI_IOC_RD_MAX_SPEED_HZ, &i); - if ((a < 0) || (b < 0)) { - DEBUG_MSG("ERROR: SPI PORT FAIL TO SET MAX SPEED\n"); - close(dev); - free(spi_device); - return LGW_SPI_ERROR; - } - - /* setting SPI to MSB first */ - i = 0; - a = ioctl(dev, SPI_IOC_WR_LSB_FIRST, &i); - b = ioctl(dev, SPI_IOC_RD_LSB_FIRST, &i); - if ((a < 0) || (b < 0)) { - DEBUG_MSG("ERROR: SPI PORT FAIL TO SET MSB FIRST\n"); - close(dev); - free(spi_device); - return LGW_SPI_ERROR; - } - - /* setting SPI to 8 bits per word */ - i = 0; - a = ioctl(dev, SPI_IOC_WR_BITS_PER_WORD, &i); - b = ioctl(dev, SPI_IOC_RD_BITS_PER_WORD, &i); - if ((a < 0) || (b < 0)) { - DEBUG_MSG("ERROR: SPI PORT FAIL TO SET 8 BITS-PER-WORD\n"); - close(dev); - return LGW_SPI_ERROR; - } - - *spi_device = dev; - *spi_target_ptr = (void *)spi_device; - DEBUG_MSG("Note: SPI port opened and configured ok\n"); - return LGW_SPI_SUCCESS; -} - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -/* SPI release */ -int lgw_spi_close(void *spi_target) { - int spi_device; - int a; - - /* check input variables */ - CHECK_NULL(spi_target); - - /* close file & deallocate file descriptor */ - spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */ - a = close(spi_device); - free(spi_target); - - /* determine return code */ - if (a < 0) { - DEBUG_MSG("ERROR: SPI PORT FAILED TO CLOSE\n"); - return LGW_SPI_ERROR; - } else { - DEBUG_MSG("Note: SPI port closed\n"); - return LGW_SPI_SUCCESS; - } -} - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -/* Simple write */ -int lgw_spi_w(void *spi_target, uint8_t spi_mux_mode, uint8_t spi_mux_target, uint8_t address, uint8_t data) { - int spi_device; - uint8_t out_buf[3]; - uint8_t command_size; - struct spi_ioc_transfer k; - int a; - - /* check input variables */ - CHECK_NULL(spi_target); - if ((address & 0x80) != 0) { - DEBUG_MSG("WARNING: SPI address > 127\n"); - } - - spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */ - - /* prepare frame to be sent */ - if (spi_mux_mode == LGW_SPI_MUX_MODE1) { - out_buf[0] = spi_mux_target; - out_buf[1] = WRITE_ACCESS | (address & 0x7F); - out_buf[2] = data; - command_size = 3; - } else { - out_buf[0] = WRITE_ACCESS | (address & 0x7F); - out_buf[1] = data; - command_size = 2; - } - - /* I/O transaction */ - memset(&k, 0, sizeof(k)); /* clear k */ - k.tx_buf = (unsigned long) out_buf; - k.len = command_size; - k.speed_hz = SPI_SPEED; - k.cs_change = 0; - k.bits_per_word = 8; - a = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k); - - /* determine return code */ - if (a != (int)k.len) { - DEBUG_MSG("ERROR: SPI WRITE FAILURE\n"); - return LGW_SPI_ERROR; - } else { - DEBUG_MSG("Note: SPI write success\n"); - return LGW_SPI_SUCCESS; - } -} - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -/* Simple read */ -int lgw_spi_r(void *spi_target, uint8_t spi_mux_mode, uint8_t spi_mux_target, uint8_t address, uint8_t *data) { - int spi_device; - uint8_t out_buf[3]; - uint8_t command_size; - uint8_t in_buf[ARRAY_SIZE(out_buf)]; - struct spi_ioc_transfer k; - int a; - - /* check input variables */ - CHECK_NULL(spi_target); - if ((address & 0x80) != 0) { - DEBUG_MSG("WARNING: SPI address > 127\n"); - } - CHECK_NULL(data); - - spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */ - - /* prepare frame to be sent */ - if (spi_mux_mode == LGW_SPI_MUX_MODE1) { - out_buf[0] = spi_mux_target; - out_buf[1] = READ_ACCESS | (address & 0x7F); - out_buf[2] = 0x00; - command_size = 3; - } else { - out_buf[0] = READ_ACCESS | (address & 0x7F); - out_buf[1] = 0x00; - command_size = 2; - } - - /* I/O transaction */ - memset(&k, 0, sizeof(k)); /* clear k */ - k.tx_buf = (unsigned long) out_buf; - k.rx_buf = (unsigned long) in_buf; - k.len = command_size; - k.cs_change = 0; - a = ioctl(spi_device, SPI_IOC_MESSAGE(1), &k); - - /* determine return code */ - if (a != (int)k.len) { - DEBUG_MSG("ERROR: SPI READ FAILURE\n"); - return LGW_SPI_ERROR; - } else { - DEBUG_MSG("Note: SPI read success\n"); - *data = in_buf[command_size - 1]; - return LGW_SPI_SUCCESS; - } -} - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -/* Burst (multiple-byte) write */ -int lgw_spi_wb(void *spi_target, uint8_t spi_mux_mode, uint8_t spi_mux_target, uint8_t address, uint8_t *data, uint16_t size) { - int spi_device; - uint8_t command[2]; - uint8_t command_size; - struct spi_ioc_transfer k[2]; - int size_to_do, chunk_size, offset; - int byte_transfered = 0; - int i; - - /* check input parameters */ - CHECK_NULL(spi_target); - if ((address & 0x80) != 0) { - DEBUG_MSG("WARNING: SPI address > 127\n"); - } - CHECK_NULL(data); - if (size == 0) { - DEBUG_MSG("ERROR: BURST OF NULL LENGTH\n"); - return LGW_SPI_ERROR; - } - - spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */ - - /* prepare command byte */ - if (spi_mux_mode == LGW_SPI_MUX_MODE1) { - command[0] = spi_mux_target; - command[1] = WRITE_ACCESS | (address & 0x7F); - command_size = 2; - } else { - command[0] = WRITE_ACCESS | (address & 0x7F); - command_size = 1; - } - size_to_do = size; - - /* I/O transaction */ - memset(&k, 0, sizeof(k)); /* clear k */ - k[0].tx_buf = (unsigned long) &command[0]; - k[0].len = command_size; - k[0].cs_change = 0; - k[1].cs_change = 0; - for (i=0; size_to_do > 0; ++i) { - chunk_size = (size_to_do < LGW_BURST_CHUNK) ? size_to_do : LGW_BURST_CHUNK; - offset = i * LGW_BURST_CHUNK; - k[1].tx_buf = (unsigned long)(data + offset); - k[1].len = chunk_size; - byte_transfered += (ioctl(spi_device, SPI_IOC_MESSAGE(2), &k) - k[0].len ); - DEBUG_PRINTF("BURST WRITE: to trans %d # chunk %d # transferred %d \n", size_to_do, chunk_size, byte_transfered); - size_to_do -= chunk_size; /* subtract the quantity of data already transferred */ - } - - /* determine return code */ - if (byte_transfered != size) { - DEBUG_MSG("ERROR: SPI BURST WRITE FAILURE\n"); - return LGW_SPI_ERROR; - } else { - DEBUG_MSG("Note: SPI burst write success\n"); - return LGW_SPI_SUCCESS; - } -} - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - -/* Burst (multiple-byte) read */ -int lgw_spi_rb(void *spi_target, uint8_t spi_mux_mode, uint8_t spi_mux_target, uint8_t address, uint8_t *data, uint16_t size) { - int spi_device; - uint8_t command[2]; - uint8_t command_size; - struct spi_ioc_transfer k[2]; - int size_to_do, chunk_size, offset; - int byte_transfered = 0; - int i; - - /* check input parameters */ - CHECK_NULL(spi_target); - if ((address & 0x80) != 0) { - DEBUG_MSG("WARNING: SPI address > 127\n"); - } - CHECK_NULL(data); - if (size == 0) { - DEBUG_MSG("ERROR: BURST OF NULL LENGTH\n"); - return LGW_SPI_ERROR; - } - - spi_device = *(int *)spi_target; /* must check that spi_target is not null beforehand */ - - /* prepare command byte */ - if (spi_mux_mode == LGW_SPI_MUX_MODE1) { - command[0] = spi_mux_target; - command[1] = READ_ACCESS | (address & 0x7F); - command_size = 2; - } else { - command[0] = READ_ACCESS | (address & 0x7F); - command_size = 1; - } - size_to_do = size; - - /* I/O transaction */ - memset(&k, 0, sizeof(k)); /* clear k */ - k[0].tx_buf = (unsigned long) &command[0]; - k[0].len = command_size; - k[0].cs_change = 0; - k[1].cs_change = 0; - for (i=0; size_to_do > 0; ++i) { - chunk_size = (size_to_do < LGW_BURST_CHUNK) ? size_to_do : LGW_BURST_CHUNK; - offset = i * LGW_BURST_CHUNK; - k[1].rx_buf = (unsigned long)(data + offset); - k[1].len = chunk_size; - byte_transfered += (ioctl(spi_device, SPI_IOC_MESSAGE(2), &k) - k[0].len ); - DEBUG_PRINTF("BURST READ: to trans %d # chunk %d # transferred %d \n", size_to_do, chunk_size, byte_transfered); - size_to_do -= chunk_size; /* subtract the quantity of data already transferred */ - } - - /* determine return code */ - if (byte_transfered != size) { - DEBUG_MSG("ERROR: SPI BURST READ FAILURE\n"); - return LGW_SPI_ERROR; - } else { - DEBUG_MSG("Note: SPI burst read success\n"); - return LGW_SPI_SUCCESS; - } -} - -/* --- EOF ------------------------------------------------------------------ */ diff --git a/lora/rak2285/Makefile b/lora/rak2285/Makefile deleted file mode 100644 index 439b23a..0000000 --- a/lora/rak2285/Makefile +++ /dev/null @@ -1,123 +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 - -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) - -### EOF diff --git a/lora/rak2285/install.sh b/lora/rak2285/install.sh deleted file mode 100755 index b03666e..0000000 --- a/lora/rak2285/install.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/bash - -# Stop on the first sign of trouble -set -e - -if [ $UID != 0 ]; then - echo "ERROR: Operation not permitted. Forgot sudo?" - exit 1 -fi - -SCRIPT_DIR=$(pwd) - -# Request gateway configuration data -# There are two ways to do it, manually specify everything -# or rely on the gateway EUI and retrieve settings files from remote (recommended) -echo "Gateway configuration:" - -# Install LoRaWAN packet forwarder repositories -INSTALL_DIR="./" -if [ ! -d "$INSTALL_DIR" ]; then mkdir $INSTALL_DIR; fi -pushd $INSTALL_DIR - -# Build LoRa gateway app - -wget https://github.com/Lora-net/sx1302_hal/archive/V1.0.5.tar.gz -O ./rak2285.tar.gz - -tar -zxvf ./rak2285.tar.gz -#mv sx1302_hal-1.0.5 lora_gateway -pushd sx1302_hal-1.0.5 -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 - -#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 -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 -mv $INSTALL_DIR/packet_forwarder/lora_pkt_fwd $INSTALL_DIR/packet_forwarder/lora_pkt_fwd_bak -mkdir -p $INSTALL_DIR/packet_forwarder/lora_pkt_fwd -mv $INSTALL_DIR/packet_forwarder/lora_pkt_fwd_bak $INSTALL_DIR/packet_forwarder/lora_pkt_fwd/lora_pkt_fwd -cp global_conf $INSTALL_DIR/packet_forwarder/lora_pkt_fwd/ -rf -cp global_conf/global_conf.eu_863_870.json $INSTALL_DIR/packet_forwarder/lora_pkt_fwd/global_conf.json -cp reset_lgw.sh $INSTALL_DIR/packet_forwarder/lora_pkt_fwd/reset_lgw.sh -sed -i "s/^.*server_address.*$/\t\"server_address\": \"127.0.0.1\",/" $INSTALL_DIR/packet_forwarder/lora_pkt_fwd/global_conf.json -rm -f $INSTALL_DIR/packet_forwarder/lora_pkt_fwd/local_conf.json diff --git a/lora/rak2285/lora_pkt_fwd.c b/lora/rak2285/lora_pkt_fwd.c deleted file mode 100644 index bd2cc13..0000000 --- a/lora/rak2285/lora_pkt_fwd.c +++ /dev/null @@ -1,3308 +0,0 @@ -/* - / _____) _ | | -( (____ _____ ____ _| |_ _____ ____| |__ - \____ \| ___ | (_ _) ___ |/ ___) _ \ - _____) ) ____| | | || |_| ____( (___| | | | -(______/|_____)_|_|_| \__)_____)\____)_| |_| - (C)2019 Semtech - -Description: - Configure Lora concentrator and forward packets to a server - Use GPS for packet timestamping. - Send a becon at a regular interval without server intervention - -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, snprintf, fopen, fputs */ -#include /* PRIx64, PRIu64... */ - -#include /* memset */ -#include /* sigaction */ -#include /* time, clock_gettime, strftime, gmtime */ -#include /* timeval */ -#include /* getopt, access */ -#include /* atoi, exit */ -#include /* error messages */ -#include /* modf */ - -#include /* socket specific definitions */ -#include /* INET constants and stuff */ -#include /* IP address conversion stuff */ -#include /* gai_strerror */ - -#include - -#include "trace.h" -#include "jitqueue.h" -#include "parson.h" -#include "base64.h" -#include "loragw_hal.h" -#include "loragw_aux.h" -#include "loragw_reg.h" -#include "loragw_gps.h" - -/* -------------------------------------------------------------------------- */ -/* --- PRIVATE MACROS ------------------------------------------------------- */ - -#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -#define STRINGIFY(x) #x -#define STR(x) STRINGIFY(x) - -/* -------------------------------------------------------------------------- */ -/* --- PRIVATE CONSTANTS ---------------------------------------------------- */ - -#ifndef VERSION_STRING - #define VERSION_STRING "undefined" -#endif - -#define JSON_CONF_DEFAULT "global_conf.json" -#define JSON_CONF_LOCAL "local_conf.json" - -#define DEFAULT_SERVER 127.0.0.1 /* hostname also supported */ -#define DEFAULT_PORT_UP 1780 -#define DEFAULT_PORT_DW 1782 -#define DEFAULT_KEEPALIVE 5 /* default time interval for downstream keep-alive packet */ -#define DEFAULT_STAT 30 /* default time interval for statistics */ -#define PUSH_TIMEOUT_MS 100 -#define PULL_TIMEOUT_MS 200 -#define GPS_REF_MAX_AGE 30 /* maximum admitted delay in seconds of GPS loss before considering latest GPS sync unusable */ -#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_JSON_RXPK_FRAME_FORMAT 1 - -#define XERR_INIT_AVG 128 /* 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 -#define PKT_PUSH_ACK 1 -#define PKT_PULL_DATA 2 -#define PKT_PULL_RESP 3 -#define PKT_PULL_ACK 4 -#define PKT_TX_ACK 5 - -#define NB_PKT_MAX 255 /* max number of packets per fetch/send cycle */ - -#define MIN_LORA_PREAMB 6 /* minimum Lora preamble length for this application */ -#define STD_LORA_PREAMB 8 -#define MIN_FSK_PREAMB 3 /* minimum FSK preamble length for this application */ -#define STD_FSK_PREAMB 5 - -#define STATUS_SIZE 200 -#define TX_BUFF_SIZE ((540 * NB_PKT_MAX) + 30 + STATUS_SIZE) -#define ACK_BUFF_SIZE 64 - -#define UNIX_GPS_EPOCH_OFFSET 315964800 /* Number of seconds ellapsed between 01.Jan.1970 00:00:00 - and 06.Jan.1980 00:00:00 */ - -#define DEFAULT_BEACON_FREQ_HZ 869525000 -#define DEFAULT_BEACON_FREQ_NB 1 -#define DEFAULT_BEACON_FREQ_STEP 0 -#define DEFAULT_BEACON_DATARATE 9 -#define DEFAULT_BEACON_BW_HZ 125000 -#define DEFAULT_BEACON_POWER 14 -#define DEFAULT_BEACON_INFODESC 0 - -/* -------------------------------------------------------------------------- */ -/* --- PRIVATE VARIABLES (GLOBAL) ------------------------------------------- */ - -/* signal handling variables */ -volatile bool exit_sig = false; /* 1 -> application terminates cleanly (shut down hardware, close open files, etc) */ -volatile bool quit_sig = false; /* 1 -> application terminates without shutting down the hardware */ - -/* packets filtering configuration variables */ -static bool fwd_valid_pkt = true; /* packets with PAYLOAD CRC OK are forwarded */ -static bool fwd_error_pkt = false; /* packets with PAYLOAD CRC ERROR are NOT forwarded */ -static bool fwd_nocrc_pkt = false; /* packets with NO PAYLOAD CRC are NOT forwarded */ - -/* network configuration variables */ -static uint64_t lgwm = 0; /* Lora gateway MAC address */ -static char serv_addr[64] = STR(DEFAULT_SERVER); /* address of the server (host name or IPv4/IPv6) */ -static char serv_port_up[8] = STR(DEFAULT_PORT_UP); /* server port for upstream traffic */ -static char serv_port_down[8] = STR(DEFAULT_PORT_DW); /* server port for downstream traffic */ -static int keepalive_time = DEFAULT_KEEPALIVE; /* send a PULL_DATA request every X seconds, negative = disabled */ - -/* statistics collection configuration variables */ -static unsigned stat_interval = DEFAULT_STAT; /* time interval (in sec) at which statistics are collected and displayed */ - -/* gateway <-> MAC protocol variables */ -static uint32_t net_mac_h; /* Most Significant Nibble, network order */ -static uint32_t net_mac_l; /* Least Significant Nibble, network order */ - -/* network sockets */ -static int sock_up; /* socket for upstream traffic */ -static int sock_down; /* socket for downstream traffic */ - -/* network protocol variables */ -static struct timeval push_timeout_half = {0, (PUSH_TIMEOUT_MS * 500)}; /* cut in half, critical for throughput */ -static struct timeval pull_timeout = {0, (PULL_TIMEOUT_MS * 1000)}; /* non critical for throughput */ - -/* hardware access control and correction */ -pthread_mutex_t mx_concent = PTHREAD_MUTEX_INITIALIZER; /* control access to the concentrator */ -static pthread_mutex_t mx_xcorr = PTHREAD_MUTEX_INITIALIZER; /* control access to the XTAL correction */ -static bool xtal_correct_ok = false; /* set true when XTAL correction is stable enough */ -static double xtal_correct = 1.0; - -/* GPS configuration and synchronization */ -static char gps_tty_path[64] = "\0"; /* path of the TTY port GPS is connected on */ -static int gps_tty_fd = -1; /* file descriptor of the GPS TTY port */ -static bool gps_enabled = false; /* is GPS enabled on that gateway ? */ - -/* GPS time reference */ -static pthread_mutex_t mx_timeref = PTHREAD_MUTEX_INITIALIZER; /* control access to GPS time reference */ -static bool gps_ref_valid; /* is GPS reference acceptable (ie. not too old) */ -static struct tref time_reference_gps; /* time reference used for GPS <-> timestamp conversion */ - -/* Reference coordinates, for broadcasting (beacon) */ -static struct coord_s reference_coord; - -/* Enable faking the GPS coordinates of the gateway */ -static bool gps_fake_enable; /* enable the feature */ - -/* measurements to establish statistics */ -static pthread_mutex_t mx_meas_up = PTHREAD_MUTEX_INITIALIZER; /* control access to the upstream measurements */ -static uint32_t meas_nb_rx_rcv = 0; /* count packets received */ -static uint32_t meas_nb_rx_ok = 0; /* count packets received with PAYLOAD CRC OK */ -static uint32_t meas_nb_rx_bad = 0; /* count packets received with PAYLOAD CRC ERROR */ -static uint32_t meas_nb_rx_nocrc = 0; /* count packets received with NO PAYLOAD CRC */ -static uint32_t meas_up_pkt_fwd = 0; /* number of radio packet forwarded to the server */ -static uint32_t meas_up_network_byte = 0; /* sum of UDP bytes sent for upstream traffic */ -static uint32_t meas_up_payload_byte = 0; /* sum of radio payload bytes sent for upstream traffic */ -static uint32_t meas_up_dgram_sent = 0; /* number of datagrams sent for upstream traffic */ -static uint32_t meas_up_ack_rcv = 0; /* number of datagrams acknowledged for upstream traffic */ - -static pthread_mutex_t mx_meas_dw = PTHREAD_MUTEX_INITIALIZER; /* control access to the downstream measurements */ -static uint32_t meas_dw_pull_sent = 0; /* number of PULL requests sent for downstream traffic */ -static uint32_t meas_dw_ack_rcv = 0; /* number of PULL requests acknowledged for downstream traffic */ -static uint32_t meas_dw_dgram_rcv = 0; /* count PULL response packets received for downstream traffic */ -static uint32_t meas_dw_network_byte = 0; /* sum of UDP bytes sent for upstream traffic */ -static uint32_t meas_dw_payload_byte = 0; /* sum of radio payload bytes sent for upstream traffic */ -static uint32_t meas_nb_tx_ok = 0; /* count packets emitted successfully */ -static uint32_t meas_nb_tx_fail = 0; /* count packets were TX failed for other reasons */ -static uint32_t meas_nb_tx_requested = 0; /* count TX request from server (downlinks) */ -static uint32_t meas_nb_tx_rejected_collision_packet = 0; /* count packets were TX request were rejected due to collision with another packet already programmed */ -static uint32_t meas_nb_tx_rejected_collision_beacon = 0; /* count packets were TX request were rejected due to collision with a beacon already programmed */ -static uint32_t meas_nb_tx_rejected_too_late = 0; /* count packets were TX request were rejected because it is too late to program it */ -static uint32_t meas_nb_tx_rejected_too_early = 0; /* count packets were TX request were rejected because timestamp is too much in advance */ -static uint32_t meas_nb_beacon_queued = 0; /* count beacon inserted in jit queue */ -static uint32_t meas_nb_beacon_sent = 0; /* count beacon actually sent to concentrator */ -static uint32_t meas_nb_beacon_rejected = 0; /* count beacon rejected for queuing */ - -static pthread_mutex_t mx_meas_gps = PTHREAD_MUTEX_INITIALIZER; /* control access to the GPS statistics */ -static bool gps_coord_valid; /* could we get valid GPS coordinates ? */ -static struct coord_s meas_gps_coord; /* GPS position of the gateway */ -static struct coord_s meas_gps_err; /* GPS position of the gateway */ - -static pthread_mutex_t mx_stat_rep = PTHREAD_MUTEX_INITIALIZER; /* control access to the status report */ -static bool report_ready = false; /* true when there is a new report to send to the server */ -static char status_report[STATUS_SIZE]; /* status report as a JSON object */ - -/* beacon parameters */ -static uint32_t beacon_period = 0; /* set beaconing period, must be a sub-multiple of 86400, the nb of sec in a day */ -static uint32_t beacon_freq_hz = DEFAULT_BEACON_FREQ_HZ; /* set beacon TX frequency, in Hz */ -static uint8_t beacon_freq_nb = DEFAULT_BEACON_FREQ_NB; /* set number of beaconing channels beacon */ -static uint32_t beacon_freq_step = DEFAULT_BEACON_FREQ_STEP; /* set frequency step between beacon channels, in Hz */ -static uint8_t beacon_datarate = DEFAULT_BEACON_DATARATE; /* set beacon datarate (SF) */ -static uint32_t beacon_bw_hz = DEFAULT_BEACON_BW_HZ; /* set beacon bandwidth, in Hz */ -static int8_t beacon_power = DEFAULT_BEACON_POWER; /* set beacon TX power, in dBm */ -static uint8_t beacon_infodesc = DEFAULT_BEACON_INFODESC; /* set beacon information descriptor */ - -/* auto-quit function */ -static uint32_t autoquit_threshold = 0; /* enable auto-quit after a number of non-acknowledged PULL_DATA (0 = disabled)*/ - -/* Just In Time TX scheduling */ -static struct jit_queue_s jit_queue[LGW_RF_CHAIN_NB]; - -/* Gateway specificities */ -static int8_t antenna_gain = 0; - -/* TX capabilities */ -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 uint32_t nb_pkt_log[LGW_IF_CHAIN_NB][8]; /* [CH][SF] */ -static uint32_t nb_pkt_received_lora = 0; -static uint32_t nb_pkt_received_fsk = 0; - -static struct lgw_conf_debug_s debugconf; -static uint32_t nb_pkt_received_ref[16]; - -/* -------------------------------------------------------------------------- */ -/* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */ - -static void usage(void); - -static void sig_handler(int sigio); - -static int parse_SX130x_configuration(const char * conf_file); - -static int parse_gateway_configuration(const char * conf_file); - -static int parse_debug_configuration(const char * conf_file); - -static uint16_t crc16(const uint8_t * data, unsigned size); - -static double difftimespec(struct timespec end, struct timespec beginning); - -static void gps_process_sync(void); - -static void gps_process_coords(void); - -static int get_tx_gain_lut_index(uint8_t rf_chain, int8_t rf_power, uint8_t * lut_index); - -/* threads */ -void thread_up(void); -void thread_down(void); -void thread_jit(void); -void thread_gps(void); -void thread_valid(void); - -/* -------------------------------------------------------------------------- */ -/* --- PRIVATE FUNCTIONS DEFINITION ----------------------------------------- */ - -static void usage( void ) -{ - printf("~~~ Library version string~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); - printf(" %s\n", lgw_version_info()); - printf("~~~ Available options ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); - printf(" -h print this help\n"); - printf(" -c use config file other than 'global_conf.json'\n"); - printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"); -} - -static void sig_handler(int sigio) { - if (sigio == SIGQUIT) { - quit_sig = true; - } else if ((sigio == SIGINT) || (sigio == SIGTERM)) { - exit_sig = true; - } - return; -} - -static int parse_SX130x_configuration(const char * conf_file) { - int i, j; - 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"; - JSON_Value *root_val = NULL; - JSON_Value *val = NULL; - JSON_Object *conf_obj = NULL; - JSON_Object *conf_txgain_obj; - JSON_Object *conf_ts_obj; - JSON_Array *conf_txlut_array; - - struct lgw_conf_board_s boardconf; - struct lgw_conf_rxrf_s rfconf; - struct lgw_conf_rxif_s ifconf; - struct lgw_conf_timestamp_s tsconf; - uint32_t sf, bw, fdev; - bool sx1250_tx_lut; - - /* try to parse JSON */ - root_val = json_parse_file_with_comments(conf_file); - if (root_val == NULL) { - MSG("ERROR: %s is not a valid JSON file\n", conf_file); - exit(EXIT_FAILURE); - } - - /* point to the gateway configuration object */ - conf_obj = json_object_get_object(json_value_get_object(root_val), conf_obj_name); - if (conf_obj == NULL) { - MSG("INFO: %s does not contain a JSON object named %s\n", conf_file, conf_obj_name); - return -1; - } else { - MSG("INFO: %s does contain a JSON object named %s, parsing SX1302 parameters\n", conf_file, conf_obj_name); - } - - /* set board configuration */ - memset(&boardconf, 0, sizeof boardconf); /* initialize configuration structure */ - str = json_object_get_string(conf_obj, "spidev_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 */ - } else { - MSG("ERROR: spidev 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); - } else { - MSG("WARNING: Data type for lorawan_public seems wrong, please check\n"); - boardconf.lorawan_public = false; - } - val = json_object_get_value(conf_obj, "clksrc"); /* fetch value (if possible) */ - if (json_value_get_type(val) == JSONNumber) { - boardconf.clksrc = (uint8_t)json_value_get_number(val); - } else { - MSG("WARNING: Data type for clksrc seems wrong, please check\n"); - boardconf.clksrc = 0; - } - val = json_object_get_value(conf_obj, "full_duplex"); /* fetch value (if possible) */ - if (json_value_get_type(val) == JSONBoolean) { - boardconf.full_duplex = (bool)json_value_get_boolean(val); - } else { - 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); - /* all parameters parsed, submitting configuration to the HAL */ - if (lgw_board_setconf(&boardconf) != LGW_HAL_SUCCESS) { - MSG("ERROR: Failed to configure board\n"); - return -1; - } - - /* set antenna gain configuration */ - val = json_object_get_value(conf_obj, "antenna_gain"); /* fetch value (if possible) */ - if (val != NULL) { - if (json_value_get_type(val) == JSONNumber) { - antenna_gain = (int8_t)json_value_get_number(val); - } else { - MSG("WARNING: Data type for antenna_gain seems wrong, please check\n"); - antenna_gain = 0; - } - } - MSG("INFO: antenna_gain %d dBi\n", antenna_gain); - - /* set timestamp configuration */ - conf_ts_obj = json_object_get_object(conf_obj, "precision_timestamp"); - if (conf_ts_obj == NULL) { - MSG("INFO: %s does not contain a JSON object for precision 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); - } else { - MSG("WARNING: Data type for precision_timestamp.enable seems wrong, please check\n"); - tsconf.enable_precision_ts = 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); - } else { - MSG("WARNING: Data type for precision_timestamp.nb_symbols seems wrong, please check\n"); - tsconf.nb_symbols = 1; - } - MSG("INFO: Configuring precision timestamp: max_ts_metrics:%u, nb_symbols:%u\n", tsconf.max_ts_metrics, tsconf.nb_symbols); - - /* all parameters parsed, submitting configuration to the HAL */ - if (lgw_timestamp_setconf(&tsconf) != LGW_HAL_SUCCESS) { - MSG("ERROR: Failed to configure precision timestamp\n"); - return -1; - } - } else { - MSG("INFO: Configuring legacy timestamp\n"); - } - } - - /* set configuration for RF chains */ - for (i = 0; i < LGW_RF_CHAIN_NB; ++i) { - memset(&rfconf, 0, sizeof rfconf); /* initialize configuration structure */ - snprintf(param_name, sizeof param_name, "radio_%i", i); /* compose parameter path inside JSON structure */ - val = json_object_get_value(conf_obj, param_name); /* fetch value (if possible) */ - if (json_value_get_type(val) != JSONObject) { - MSG("INFO: no configuration for radio %i\n", i); - continue; - } - /* there is an object to configure that radio, let's parse it */ - snprintf(param_name, sizeof param_name, "radio_%i.enable", i); - val = json_object_dotget_value(conf_obj, param_name); - if (json_value_get_type(val) == JSONBoolean) { - rfconf.enable = (bool)json_value_get_boolean(val); - } else { - rfconf.enable = false; - } - if (rfconf.enable == false) { /* radio disabled, nothing else to parse */ - MSG("INFO: radio %i disabled\n", i); - } else { /* radio enabled, will parse the other parameters */ - snprintf(param_name, sizeof param_name, "radio_%i.freq", i); - rfconf.freq_hz = (uint32_t)json_object_dotget_number(conf_obj, param_name); - snprintf(param_name, sizeof param_name, "radio_%i.rssi_offset", i); - rfconf.rssi_offset = (float)json_object_dotget_number(conf_obj, param_name); - snprintf(param_name, sizeof param_name, "radio_%i.rssi_tcomp.coeff_a", i); - rfconf.rssi_tcomp.coeff_a = (float)json_object_dotget_number(conf_obj, param_name); - snprintf(param_name, sizeof param_name, "radio_%i.rssi_tcomp.coeff_b", i); - rfconf.rssi_tcomp.coeff_b = (float)json_object_dotget_number(conf_obj, param_name); - snprintf(param_name, sizeof param_name, "radio_%i.rssi_tcomp.coeff_c", i); - rfconf.rssi_tcomp.coeff_c = (float)json_object_dotget_number(conf_obj, param_name); - snprintf(param_name, sizeof param_name, "radio_%i.rssi_tcomp.coeff_d", i); - rfconf.rssi_tcomp.coeff_d = (float)json_object_dotget_number(conf_obj, param_name); - snprintf(param_name, sizeof param_name, "radio_%i.rssi_tcomp.coeff_e", i); - rfconf.rssi_tcomp.coeff_e = (float)json_object_dotget_number(conf_obj, param_name); - snprintf(param_name, sizeof param_name, "radio_%i.type", i); - str = json_object_dotget_string(conf_obj, param_name); - if (!strncmp(str, "SX1255", 6)) { - rfconf.type = LGW_RADIO_TYPE_SX1255; - } else if (!strncmp(str, "SX1257", 6)) { - rfconf.type = LGW_RADIO_TYPE_SX1257; - } else if (!strncmp(str, "SX1250", 6)) { - rfconf.type = LGW_RADIO_TYPE_SX1250; - } else { - MSG("WARNING: invalid radio type: %s (should be SX1255 or SX1257 or SX1250)\n", str); - } - snprintf(param_name, sizeof param_name, "radio_%i.single_input_mode", i); - val = json_object_dotget_value(conf_obj, param_name); - if (json_value_get_type(val) == JSONBoolean) { - rfconf.single_input_mode = (bool)json_value_get_boolean(val); - } else { - rfconf.single_input_mode = false; - } - - snprintf(param_name, sizeof param_name, "radio_%i.tx_enable", i); - val = json_object_dotget_value(conf_obj, param_name); - if (json_value_get_type(val) == JSONBoolean) { - rfconf.tx_enable = (bool)json_value_get_boolean(val); - if (rfconf.tx_enable == true) { - /* tx is enabled on this rf chain, we need its frequency range */ - snprintf(param_name, sizeof param_name, "radio_%i.tx_freq_min", i); - tx_freq_min[i] = (uint32_t)json_object_dotget_number(conf_obj, param_name); - snprintf(param_name, sizeof param_name, "radio_%i.tx_freq_max", i); - tx_freq_max[i] = (uint32_t)json_object_dotget_number(conf_obj, param_name); - if ((tx_freq_min[i] == 0) || (tx_freq_max[i] == 0)) { - MSG("WARNING: no frequency range specified for TX rf chain %d\n", i); - } - - /* set configuration for tx gains */ - memset(&txlut[i], 0, sizeof txlut[i]); /* initialize configuration structure */ - snprintf(param_name, sizeof param_name, "radio_%i.tx_gain_lut", i); - conf_txlut_array = json_object_dotget_array(conf_obj, param_name); - if (conf_txlut_array != NULL) { - txlut[i].size = json_array_get_count(conf_txlut_array); - /* Detect if we have a sx125x or sx1250 configuration */ - conf_txgain_obj = json_array_get_object(conf_txlut_array, 0); - val = json_object_dotget_value(conf_txgain_obj, "pwr_idx"); - if (val != NULL) { - printf("INFO: Configuring Tx Gain LUT for rf_chain %u with %u indexes for sx1250\n", i, txlut[i].size); - sx1250_tx_lut = true; - } else { - printf("INFO: Configuring Tx Gain LUT for rf_chain %u with %u indexes for sx125x\n", i, txlut[i].size); - sx1250_tx_lut = false; - } - /* Parse the table */ - for (j = 0; j < (int)txlut[i].size; j++) { - /* Sanity check */ - if (j >= TX_GAIN_LUT_SIZE_MAX) { - printf("ERROR: TX Gain LUT [%u] index %d not supported, skip it\n", i, j); - break; - } - /* Get TX gain object from LUT */ - conf_txgain_obj = json_array_get_object(conf_txlut_array, j); - /* rf power */ - val = json_object_dotget_value(conf_txgain_obj, "rf_power"); - if (json_value_get_type(val) == JSONNumber) { - txlut[i].lut[j].rf_power = (int8_t)json_value_get_number(val); - } else { - printf("WARNING: Data type for %s[%d] seems wrong, please check\n", "rf_power", j); - txlut[i].lut[j].rf_power = 0; - } - /* PA gain */ - val = json_object_dotget_value(conf_txgain_obj, "pa_gain"); - if (json_value_get_type(val) == JSONNumber) { - txlut[i].lut[j].pa_gain = (uint8_t)json_value_get_number(val); - } else { - printf("WARNING: Data type for %s[%d] seems wrong, please check\n", "pa_gain", j); - txlut[i].lut[j].pa_gain = 0; - } - if (sx1250_tx_lut == false) { - /* DIG gain */ - val = json_object_dotget_value(conf_txgain_obj, "dig_gain"); - if (json_value_get_type(val) == JSONNumber) { - txlut[i].lut[j].dig_gain = (uint8_t)json_value_get_number(val); - } else { - printf("WARNING: Data type for %s[%d] seems wrong, please check\n", "dig_gain", j); - txlut[i].lut[j].dig_gain = 0; - } - /* DAC gain */ - val = json_object_dotget_value(conf_txgain_obj, "dac_gain"); - if (json_value_get_type(val) == JSONNumber) { - txlut[i].lut[j].dac_gain = (uint8_t)json_value_get_number(val); - } else { - printf("WARNING: Data type for %s[%d] seems wrong, please check\n", "dac_gain", j); - txlut[i].lut[j].dac_gain = 3; /* This is the only dac_gain supported for now */ - } - /* MIX gain */ - val = json_object_dotget_value(conf_txgain_obj, "mix_gain"); - if (json_value_get_type(val) == JSONNumber) { - txlut[i].lut[j].mix_gain = (uint8_t)json_value_get_number(val); - } else { - printf("WARNING: Data type for %s[%d] seems wrong, please check\n", "mix_gain", j); - txlut[i].lut[j].mix_gain = 0; - } - } else { - /* TODO: rework this, should not be needed for sx1250 */ - txlut[i].lut[j].mix_gain = 5; - - /* power index */ - val = json_object_dotget_value(conf_txgain_obj, "pwr_idx"); - if (json_value_get_type(val) == JSONNumber) { - txlut[i].lut[j].pwr_idx = (uint8_t)json_value_get_number(val); - } else { - printf("WARNING: Data type for %s[%d] seems wrong, please check\n", "pwr_idx", j); - txlut[i].lut[j].pwr_idx = 0; - } - } - } - /* all parameters parsed, submitting configuration to the HAL */ - if (txlut[i].size > 0) { - if (lgw_txgain_setconf(i, &txlut[i]) != LGW_HAL_SUCCESS) { - MSG("ERROR: Failed to configure concentrator TX Gain LUT for rf_chain %u\n", i); - return -1; - } - } else { - MSG("WARNING: No TX gain LUT defined for rf_chain %u\n", i); - } - } else { - MSG("WARNING: No TX gain LUT defined for rf_chain %u\n", i); - } - } - } else { - rfconf.tx_enable = false; - } - MSG("INFO: radio %i enabled (type %s), center frequency %u, RSSI offset %f, tx enabled %d, single input mode %d\n", i, str, rfconf.freq_hz, rfconf.rssi_offset, rfconf.tx_enable, rfconf.single_input_mode); - } - /* all parameters parsed, submitting configuration to the HAL */ - if (lgw_rxrf_setconf(i, &rfconf) != LGW_HAL_SUCCESS) { - MSG("ERROR: invalid configuration for radio %i\n", i); - return -1; - } - } - - /* set configuration for Lora multi-SF channels (bandwidth cannot be set) */ - for (i = 0; i < LGW_MULTI_NB; ++i) { - memset(&ifconf, 0, sizeof ifconf); /* initialize configuration structure */ - snprintf(param_name, sizeof param_name, "chan_multiSF_%i", i); /* compose parameter path inside JSON structure */ - val = json_object_get_value(conf_obj, param_name); /* fetch value (if possible) */ - if (json_value_get_type(val) != JSONObject) { - MSG("INFO: no configuration for Lora multi-SF channel %i\n", i); - continue; - } - /* there is an object to configure that Lora multi-SF channel, let's parse it */ - snprintf(param_name, sizeof param_name, "chan_multiSF_%i.enable", i); - val = json_object_dotget_value(conf_obj, param_name); - if (json_value_get_type(val) == JSONBoolean) { - ifconf.enable = (bool)json_value_get_boolean(val); - } else { - ifconf.enable = false; - } - if (ifconf.enable == false) { /* Lora multi-SF channel disabled, nothing else to parse */ - MSG("INFO: Lora multi-SF channel %i disabled\n", i); - } else { /* Lora multi-SF channel enabled, will parse the other parameters */ - snprintf(param_name, sizeof param_name, "chan_multiSF_%i.radio", i); - ifconf.rf_chain = (uint32_t)json_object_dotget_number(conf_obj, param_name); - snprintf(param_name, sizeof param_name, "chan_multiSF_%i.if", i); - ifconf.freq_hz = (int32_t)json_object_dotget_number(conf_obj, param_name); - // TODO: handle individual SF enabling and disabling (spread_factor) - MSG("INFO: Lora multi-SF channel %i> radio %i, IF %i Hz, 125 kHz bw, SF 5 to 12\n", i, ifconf.rf_chain, ifconf.freq_hz); - } - /* all parameters parsed, submitting configuration to the HAL */ - if (lgw_rxif_setconf(i, &ifconf) != LGW_HAL_SUCCESS) { - MSG("ERROR: invalid configuration for Lora multi-SF channel %i\n", i); - return -1; - } - } - - /* set configuration for Lora standard channel */ - memset(&ifconf, 0, sizeof ifconf); /* initialize configuration structure */ - val = json_object_get_value(conf_obj, "chan_Lora_std"); /* fetch value (if possible) */ - if (json_value_get_type(val) != JSONObject) { - MSG("INFO: no configuration for Lora standard channel\n"); - } else { - val = json_object_dotget_value(conf_obj, "chan_Lora_std.enable"); - if (json_value_get_type(val) == JSONBoolean) { - ifconf.enable = (bool)json_value_get_boolean(val); - } else { - ifconf.enable = false; - } - if (ifconf.enable == false) { - MSG("INFO: Lora standard channel %i disabled\n", i); - } else { - ifconf.rf_chain = (uint32_t)json_object_dotget_number(conf_obj, "chan_Lora_std.radio"); - ifconf.freq_hz = (int32_t)json_object_dotget_number(conf_obj, "chan_Lora_std.if"); - bw = (uint32_t)json_object_dotget_number(conf_obj, "chan_Lora_std.bandwidth"); - switch(bw) { - case 500000: ifconf.bandwidth = BW_500KHZ; break; - case 250000: ifconf.bandwidth = BW_250KHZ; break; - case 125000: ifconf.bandwidth = BW_125KHZ; break; - default: ifconf.bandwidth = BW_UNDEFINED; - } - sf = (uint32_t)json_object_dotget_number(conf_obj, "chan_Lora_std.spread_factor"); - switch(sf) { - case 5: ifconf.datarate = DR_LORA_SF5; break; - case 6: ifconf.datarate = DR_LORA_SF6; break; - case 7: ifconf.datarate = DR_LORA_SF7; break; - case 8: ifconf.datarate = DR_LORA_SF8; break; - case 9: ifconf.datarate = DR_LORA_SF9; break; - case 10: ifconf.datarate = DR_LORA_SF10; break; - case 11: ifconf.datarate = DR_LORA_SF11; break; - case 12: ifconf.datarate = DR_LORA_SF12; break; - default: ifconf.datarate = DR_UNDEFINED; - } - val = json_object_dotget_value(conf_obj, "chan_Lora_std.implicit_hdr"); - if (json_value_get_type(val) == JSONBoolean) { - ifconf.implicit_hdr = (bool)json_value_get_boolean(val); - } else { - ifconf.implicit_hdr = false; - } - if (ifconf.implicit_hdr == true) { - val = json_object_dotget_value(conf_obj, "chan_Lora_std.implicit_payload_length"); - if (json_value_get_type(val) == JSONNumber) { - ifconf.implicit_payload_length = (uint8_t)json_value_get_number(val); - } else { - MSG("ERROR: payload length setting is mandatory for implicit header mode\n"); - return -1; - } - val = json_object_dotget_value(conf_obj, "chan_Lora_std.implicit_crc_en"); - if (json_value_get_type(val) == JSONBoolean) { - ifconf.implicit_crc_en = (bool)json_value_get_boolean(val); - } else { - MSG("ERROR: CRC enable setting is mandatory for implicit header mode\n"); - return -1; - } - val = json_object_dotget_value(conf_obj, "chan_Lora_std.implicit_coderate"); - if (json_value_get_type(val) == JSONNumber) { - ifconf.implicit_coderate = (uint8_t)json_value_get_number(val); - } else { - MSG("ERROR: coding rate setting is mandatory for implicit header mode\n"); - return -1; - } - } - - MSG("INFO: Lora std channel> radio %i, IF %i Hz, %u Hz bw, SF %u, %s\n", ifconf.rf_chain, ifconf.freq_hz, bw, sf, (ifconf.implicit_hdr == true) ? "Implicit header" : "Explicit header"); - } - if (lgw_rxif_setconf(8, &ifconf) != LGW_HAL_SUCCESS) { - MSG("ERROR: invalid configuration for Lora standard channel\n"); - return -1; - } - } - - /* set configuration for FSK channel */ - memset(&ifconf, 0, sizeof ifconf); /* initialize configuration structure */ - val = json_object_get_value(conf_obj, "chan_FSK"); /* fetch value (if possible) */ - if (json_value_get_type(val) != JSONObject) { - MSG("INFO: no configuration for FSK channel\n"); - } else { - val = json_object_dotget_value(conf_obj, "chan_FSK.enable"); - if (json_value_get_type(val) == JSONBoolean) { - ifconf.enable = (bool)json_value_get_boolean(val); - } else { - ifconf.enable = false; - } - if (ifconf.enable == false) { - MSG("INFO: FSK channel %i disabled\n", i); - } else { - ifconf.rf_chain = (uint32_t)json_object_dotget_number(conf_obj, "chan_FSK.radio"); - ifconf.freq_hz = (int32_t)json_object_dotget_number(conf_obj, "chan_FSK.if"); - bw = (uint32_t)json_object_dotget_number(conf_obj, "chan_FSK.bandwidth"); - fdev = (uint32_t)json_object_dotget_number(conf_obj, "chan_FSK.freq_deviation"); - ifconf.datarate = (uint32_t)json_object_dotget_number(conf_obj, "chan_FSK.datarate"); - - /* if chan_FSK.bandwidth is set, it has priority over chan_FSK.freq_deviation */ - if ((bw == 0) && (fdev != 0)) { - bw = 2 * fdev + ifconf.datarate; - } - if (bw == 0) ifconf.bandwidth = BW_UNDEFINED; -#if 0 /* TODO */ - else if (bw <= 7800) ifconf.bandwidth = BW_7K8HZ; - else if (bw <= 15600) ifconf.bandwidth = BW_15K6HZ; - else if (bw <= 31200) ifconf.bandwidth = BW_31K2HZ; - else if (bw <= 62500) ifconf.bandwidth = BW_62K5HZ; -#endif - else if (bw <= 125000) ifconf.bandwidth = BW_125KHZ; - else if (bw <= 250000) ifconf.bandwidth = BW_250KHZ; - else if (bw <= 500000) ifconf.bandwidth = BW_500KHZ; - else ifconf.bandwidth = BW_UNDEFINED; - - MSG("INFO: FSK channel> radio %i, IF %i Hz, %u Hz bw, %u bps datarate\n", ifconf.rf_chain, ifconf.freq_hz, bw, ifconf.datarate); - } - if (lgw_rxif_setconf(9, &ifconf) != LGW_HAL_SUCCESS) { - MSG("ERROR: invalid configuration for FSK channel\n"); - return -1; - } - } - json_value_free(root_val); - - return 0; -} - -static int parse_gateway_configuration(const char * conf_file) { - const char conf_obj_name[] = "gateway_conf"; - JSON_Value *root_val; - JSON_Object *conf_obj = NULL; - JSON_Value *val = NULL; /* needed to detect the absence of some fields */ - const char *str; /* pointer to sub-strings in the JSON data */ - unsigned long long ull = 0; - - /* try to parse JSON */ - root_val = json_parse_file_with_comments(conf_file); - if (root_val == NULL) { - MSG("ERROR: %s is not a valid JSON file\n", conf_file); - exit(EXIT_FAILURE); - } - - /* point to the gateway configuration object */ - conf_obj = json_object_get_object(json_value_get_object(root_val), conf_obj_name); - if (conf_obj == NULL) { - MSG("INFO: %s does not contain a JSON object named %s\n", conf_file, conf_obj_name); - return -1; - } else { - MSG("INFO: %s does contain a JSON object named %s, parsing gateway parameters\n", conf_file, conf_obj_name); - } - - /* gateway unique identifier (aka MAC address) (optional) */ - str = json_object_get_string(conf_obj, "gateway_ID"); - if (str != NULL) { - sscanf(str, "%llx", &ull); - lgwm = ull; - MSG("INFO: gateway MAC address is configured to %016llX\n", ull); - } - - /* server hostname or IP address (optional) */ - str = json_object_get_string(conf_obj, "server_address"); - if (str != NULL) { - strncpy(serv_addr, str, sizeof(serv_addr) - 1); - serv_addr[sizeof serv_addr - 1] = '\0'; /* ensure string termination */ - MSG("INFO: server hostname or IP address is configured to \"%s\"\n", serv_addr); - } - - /* get up and down ports (optional) */ - val = json_object_get_value(conf_obj, "serv_port_up"); - if (val != NULL) { - snprintf(serv_port_up, sizeof serv_port_up, "%u", (uint16_t)json_value_get_number(val)); - MSG("INFO: upstream port is configured to \"%s\"\n", serv_port_up); - } - val = json_object_get_value(conf_obj, "serv_port_down"); - if (val != NULL) { - snprintf(serv_port_down, sizeof serv_port_down, "%u", (uint16_t)json_value_get_number(val)); - MSG("INFO: downstream port is configured to \"%s\"\n", serv_port_down); - } - - /* get keep-alive interval (in seconds) for downstream (optional) */ - val = json_object_get_value(conf_obj, "keepalive_interval"); - if (val != NULL) { - keepalive_time = (int)json_value_get_number(val); - MSG("INFO: downstream keep-alive interval is configured to %u seconds\n", keepalive_time); - } - - /* get interval (in seconds) for statistics display (optional) */ - val = json_object_get_value(conf_obj, "stat_interval"); - if (val != NULL) { - stat_interval = (unsigned)json_value_get_number(val); - MSG("INFO: statistics display interval is configured to %u seconds\n", stat_interval); - } - - /* get time-out value (in ms) for upstream datagrams (optional) */ - val = json_object_get_value(conf_obj, "push_timeout_ms"); - if (val != NULL) { - push_timeout_half.tv_usec = 500 * (long int)json_value_get_number(val); - MSG("INFO: upstream PUSH_DATA time-out is configured to %u ms\n", (unsigned)(push_timeout_half.tv_usec / 500)); - } - - /* packet filtering parameters */ - val = json_object_get_value(conf_obj, "forward_crc_valid"); - if (json_value_get_type(val) == JSONBoolean) { - fwd_valid_pkt = (bool)json_value_get_boolean(val); - } - MSG("INFO: packets received with a valid CRC will%s be forwarded\n", (fwd_valid_pkt ? "" : " NOT")); - val = json_object_get_value(conf_obj, "forward_crc_error"); - if (json_value_get_type(val) == JSONBoolean) { - fwd_error_pkt = (bool)json_value_get_boolean(val); - } - MSG("INFO: packets received with a CRC error will%s be forwarded\n", (fwd_error_pkt ? "" : " NOT")); - val = json_object_get_value(conf_obj, "forward_crc_disabled"); - if (json_value_get_type(val) == JSONBoolean) { - fwd_nocrc_pkt = (bool)json_value_get_boolean(val); - } - MSG("INFO: packets received with no CRC will%s be forwarded\n", (fwd_nocrc_pkt ? "" : " NOT")); - - /* GPS module TTY path (optional) */ - str = json_object_get_string(conf_obj, "gps_tty_path"); - if (str != NULL) { - strncpy(gps_tty_path, str, sizeof(gps_tty_path) - 1); - 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); - } - - /* get reference coordinates */ - val = json_object_get_value(conf_obj, "ref_latitude"); - if (val != NULL) { - reference_coord.lat = (double)json_value_get_number(val); - MSG("INFO: Reference latitude is configured to %f deg\n", reference_coord.lat); - } - val = json_object_get_value(conf_obj, "ref_longitude"); - if (val != NULL) { - reference_coord.lon = (double)json_value_get_number(val); - MSG("INFO: Reference longitude is configured to %f deg\n", reference_coord.lon); - } - val = json_object_get_value(conf_obj, "ref_altitude"); - if (val != NULL) { - reference_coord.alt = (short)json_value_get_number(val); - MSG("INFO: Reference altitude is configured to %i meters\n", reference_coord.alt); - } - - /* Gateway GPS coordinates hardcoding (aka. faking) option */ - val = json_object_get_value(conf_obj, "fake_gps"); - if (json_value_get_type(val) == JSONBoolean) { - gps_fake_enable = (bool)json_value_get_boolean(val); - if (gps_fake_enable == true) { - MSG("INFO: fake GPS is enabled\n"); - } else { - MSG("INFO: fake GPS is disabled\n"); - } - } - - /* Beacon signal period (optional) */ - val = json_object_get_value(conf_obj, "beacon_period"); - if (val != NULL) { - beacon_period = (uint32_t)json_value_get_number(val); - if ((beacon_period > 0) && (beacon_period < 6)) { - MSG("ERROR: invalid configuration for Beacon period, must be >= 6s\n"); - return -1; - } else { - MSG("INFO: Beaconing period is configured to %u seconds\n", beacon_period); - } - } - - /* Beacon TX frequency (optional) */ - val = json_object_get_value(conf_obj, "beacon_freq_hz"); - if (val != NULL) { - beacon_freq_hz = (uint32_t)json_value_get_number(val); - MSG("INFO: Beaconing signal will be emitted at %u Hz\n", beacon_freq_hz); - } - - /* Number of beacon channels (optional) */ - val = json_object_get_value(conf_obj, "beacon_freq_nb"); - if (val != NULL) { - beacon_freq_nb = (uint8_t)json_value_get_number(val); - MSG("INFO: Beaconing channel number is set to %u\n", beacon_freq_nb); - } - - /* Frequency step between beacon channels (optional) */ - val = json_object_get_value(conf_obj, "beacon_freq_step"); - if (val != NULL) { - beacon_freq_step = (uint32_t)json_value_get_number(val); - MSG("INFO: Beaconing channel frequency step is set to %uHz\n", beacon_freq_step); - } - - /* Beacon datarate (optional) */ - val = json_object_get_value(conf_obj, "beacon_datarate"); - if (val != NULL) { - beacon_datarate = (uint8_t)json_value_get_number(val); - MSG("INFO: Beaconing datarate is set to SF%d\n", beacon_datarate); - } - - /* Beacon modulation bandwidth (optional) */ - val = json_object_get_value(conf_obj, "beacon_bw_hz"); - if (val != NULL) { - beacon_bw_hz = (uint32_t)json_value_get_number(val); - MSG("INFO: Beaconing modulation bandwidth is set to %dHz\n", beacon_bw_hz); - } - - /* Beacon TX power (optional) */ - val = json_object_get_value(conf_obj, "beacon_power"); - if (val != NULL) { - beacon_power = (int8_t)json_value_get_number(val); - MSG("INFO: Beaconing TX power is set to %ddBm\n", beacon_power); - } - - /* Beacon information descriptor (optional) */ - val = json_object_get_value(conf_obj, "beacon_infodesc"); - if (val != NULL) { - beacon_infodesc = (uint8_t)json_value_get_number(val); - MSG("INFO: Beaconing information descriptor is set to %u\n", beacon_infodesc); - } - - /* Auto-quit threshold (optional) */ - val = json_object_get_value(conf_obj, "autoquit_threshold"); - if (val != NULL) { - autoquit_threshold = (uint32_t)json_value_get_number(val); - MSG("INFO: Auto-quit after %u non-acknowledged PULL_DATA\n", autoquit_threshold); - } - - /* free JSON parsing data structure */ - json_value_free(root_val); - return 0; -} - -static int parse_debug_configuration(const char * conf_file) { - int i; - const char conf_obj_name[] = "debug_conf"; - JSON_Value *root_val; - JSON_Object *conf_obj = NULL; - JSON_Array *conf_array = NULL; - JSON_Object *conf_obj_array = NULL; - const char *str; /* pointer to sub-strings in the JSON data */ - - /* Initialize structure */ - memset(&debugconf, 0, sizeof debugconf); - - /* try to parse JSON */ - root_val = json_parse_file_with_comments(conf_file); - if (root_val == NULL) { - MSG("ERROR: %s is not a valid JSON file\n", conf_file); - exit(EXIT_FAILURE); - } - - /* point to the gateway configuration object */ - conf_obj = json_object_get_object(json_value_get_object(root_val), conf_obj_name); - if (conf_obj == NULL) { - MSG("INFO: %s does not contain a JSON object named %s\n", conf_file, conf_obj_name); - json_value_free(root_val); - return -1; - } else { - MSG("INFO: %s does contain a JSON object named %s, parsing debug parameters\n", conf_file, conf_obj_name); - } - - /* Get reference payload configuration */ - conf_array = json_object_get_array (conf_obj, "ref_payload"); - if (conf_array != NULL) { - debugconf.nb_ref_payload = json_array_get_count(conf_array); - MSG("INFO: got %u debug reference payload\n", debugconf.nb_ref_payload); - - for (i = 0; i < (int)debugconf.nb_ref_payload; i++) { - conf_obj_array = json_array_get_object(conf_array, i); - /* id */ - str = json_object_get_string(conf_obj_array, "id"); - if (str != NULL) { - sscanf(str, "0x%08X", &(debugconf.ref_payload[i].id)); - MSG("INFO: reference payload ID %d is 0x%08X\n", i, debugconf.ref_payload[i].id); - } - - /* global count */ - nb_pkt_received_ref[i] = 0; - } - } - - /* 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); - 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); - } - - /* Commit configuration */ - if (lgw_debug_setconf(&debugconf) != LGW_HAL_SUCCESS) { - MSG("ERROR: Failed to configure debug\n"); - json_value_free(root_val); - return -1; - } - - /* free JSON parsing data structure */ - json_value_free(root_val); - return 0; -} - -static uint16_t crc16(const uint8_t * data, unsigned size) { - const uint16_t crc_poly = 0x1021; - const uint16_t init_val = 0x0000; - uint16_t x = init_val; - unsigned i, j; - - if (data == NULL) { - return 0; - } - - for (i=0; i 0) { - buff_index += j; - } else { - MSG("ERROR: [up] snprintf failed line %u\n", (__LINE__ - 4)); - exit(EXIT_FAILURE); - } - break; - default: - /* Do nothing */ - break; - } - /* end of JSON structure */ - memcpy((void *)(buff_ack + buff_index), (void *)"}}", 2); - buff_index += 2; - } - - buff_ack[buff_index] = 0; /* add string terminator, for safety */ - - /* send datagram to server */ - return send(sock_down, (void *)buff_ack, buff_index, 0); -} - -/* -------------------------------------------------------------------------- */ -/* --- MAIN FUNCTION -------------------------------------------------------- */ - -int main(int argc, char ** argv) -{ - struct sigaction sigact; /* SIGQUIT&SIGINT&SIGTERM signal handling */ - int i; /* loop variable and temporary variable for return value */ - int x; - int l, m; - - /* configuration file related */ - const char defaut_conf_fname[] = JSON_CONF_DEFAULT; - const char * conf_fname = defaut_conf_fname; /* pointer to a string we won't touch */ - const char default_local_conf_fname[] = JSON_CONF_LOCAL; - const char * local_conf_fname = default_local_conf_fname; - - /* threads */ - pthread_t thrid_up; - pthread_t thrid_down; - pthread_t thrid_gps; - pthread_t thrid_valid; - pthread_t thrid_jit; - - /* network socket creation */ - struct addrinfo hints; - struct addrinfo *result; /* store result of getaddrinfo */ - struct addrinfo *q; /* pointer to move into *result data */ - char host_name[64]; - char port_name[64]; - - /* variables to get local copies of measurements */ - uint32_t cp_nb_rx_rcv; - uint32_t cp_nb_rx_ok; - uint32_t cp_nb_rx_bad; - uint32_t cp_nb_rx_nocrc; - uint32_t cp_up_pkt_fwd; - uint32_t cp_up_network_byte; - uint32_t cp_up_payload_byte; - uint32_t cp_up_dgram_sent; - uint32_t cp_up_ack_rcv; - uint32_t cp_dw_pull_sent; - uint32_t cp_dw_ack_rcv; - uint32_t cp_dw_dgram_rcv; - uint32_t cp_dw_network_byte; - uint32_t cp_dw_payload_byte; - uint32_t cp_nb_tx_ok; - uint32_t cp_nb_tx_fail; - uint32_t cp_nb_tx_requested = 0; - uint32_t cp_nb_tx_rejected_collision_packet = 0; - uint32_t cp_nb_tx_rejected_collision_beacon = 0; - uint32_t cp_nb_tx_rejected_too_late = 0; - uint32_t cp_nb_tx_rejected_too_early = 0; - uint32_t cp_nb_beacon_queued = 0; - uint32_t cp_nb_beacon_sent = 0; - uint32_t cp_nb_beacon_rejected = 0; - - /* GPS coordinates variables */ - bool coord_ok = false; - struct coord_s cp_gps_coord = {0.0, 0.0, 0}; - - /* SX1302 data variables */ - uint32_t trig_tstamp; - uint32_t inst_tstamp; - uint64_t eui; -// float temperature; - - /* statistics variable */ - time_t t; - char stat_timestamp[24]; - float rx_ok_ratio; - float rx_bad_ratio; - float rx_nocrc_ratio; - float up_ack_ratio; - float dw_ack_ratio; - - /* Parse command line options */ - while( (i = getopt( argc, argv, "hc:" )) != -1 ) - { - switch( i ) - { - case 'h': - usage( ); - return EXIT_SUCCESS; - break; - - case 'c': - conf_fname = optarg; - break; - - default: - printf( "ERROR: argument parsing options, use -h option for help\n" ); - usage( ); - return EXIT_FAILURE; - } - } - - /* display version informations */ - MSG("*** Packet Forwarder ***\nVersion: " VERSION_STRING "\n"); - MSG("*** SX1302 HAL library version info ***\n%s\n***\n", lgw_version_info()); - - /* display host endianness */ - #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ - MSG("INFO: Little endian host\n"); - #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ - MSG("INFO: Big endian host\n"); - #else - MSG("INFO: Host endianness unknown\n"); - #endif - - /* load configuration files */ - if (access(conf_fname, R_OK) == 0) { /* if there is a global conf, parse it */ - MSG("INFO: found configuration file %s, parsing it\n", conf_fname); - x = parse_SX130x_configuration(conf_fname); - if (x != 0) { - exit(EXIT_FAILURE); - } - x = parse_gateway_configuration(conf_fname); - if (x != 0) { - exit(EXIT_FAILURE); - } - x = parse_debug_configuration(conf_fname); - if (x != 0) { - MSG("INFO: no debug configuration\n"); - } - } else { - MSG("ERROR: [main] failed to find any configuration file named %s\n", conf_fname); - exit(EXIT_FAILURE); - } - /* load local configuration files */ - if (access(local_conf_fname, R_OK) == 0) { /* if there is a local conf, parse it */ - MSG("INFO: found configuration file %s, parsing it\n", local_conf_fname); - x = parse_gateway_configuration(local_conf_fname); - if (x != 0) { - exit(EXIT_FAILURE); - } - } else { - MSG("ERROR: [main] failed to find any configuration file named %s\n", local_conf_fname); - exit(EXIT_FAILURE); - } - - /* Start GPS a.s.a.p., to allow it to lock */ - if (gps_tty_path[0] != '\0') { /* do not try to open GPS device if no path set */ - i = lgw_gps_enable(gps_tty_path, "ubx7", 0, &gps_tty_fd); /* HAL only supports u-blox 7 for now */ - if (i != LGW_GPS_SUCCESS) { - printf("WARNING: [main] impossible to open %s for GPS sync (check permissions)\n", gps_tty_path); - gps_enabled = false; - gps_ref_valid = false; - } else { - printf("INFO: [main] TTY port %s open for GPS synchronization\n", gps_tty_path); - gps_enabled = true; - gps_ref_valid = false; - } - } - - /* get timezone info */ - tzset(); - - /* sanity check on configuration variables */ - // TODO - - /* process some of the configuration variables */ - net_mac_h = htonl((uint32_t)(0xFFFFFFFF & (lgwm>>32))); - net_mac_l = htonl((uint32_t)(0xFFFFFFFF & lgwm )); - - /* prepare hints to open network sockets */ - memset(&hints, 0, sizeof hints); - hints.ai_family = AF_INET; /* WA: Forcing IPv4 as AF_UNSPEC makes connection on localhost to fail */ - hints.ai_socktype = SOCK_DGRAM; - - /* look for server address w/ upstream port */ - i = getaddrinfo(serv_addr, serv_port_up, &hints, &result); - if (i != 0) { - MSG("ERROR: [up] getaddrinfo on address %s (PORT %s) returned %s\n", serv_addr, serv_port_up, gai_strerror(i)); - exit(EXIT_FAILURE); - } - - /* try to open socket for upstream traffic */ - for (q=result; q!=NULL; q=q->ai_next) { - sock_up = socket(q->ai_family, q->ai_socktype,q->ai_protocol); - if (sock_up == -1) continue; /* try next field */ - else break; /* success, get out of loop */ - } - if (q == NULL) { - MSG("ERROR: [up] failed to open socket to any of server %s addresses (port %s)\n", serv_addr, serv_port_up); - 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); - MSG("INFO: [up] result %i host:%s service:%s\n", i, host_name, port_name); - ++i; - } - exit(EXIT_FAILURE); - } - - /* connect so we can send/receive packet with the server only */ - i = connect(sock_up, q->ai_addr, q->ai_addrlen); - if (i != 0) { - MSG("ERROR: [up] connect returned %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - freeaddrinfo(result); - - /* 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)); - exit(EXIT_FAILURE); - } - - /* try to open socket for downstream traffic */ - for (q=result; q!=NULL; q=q->ai_next) { - sock_down = socket(q->ai_family, q->ai_socktype,q->ai_protocol); - if (sock_down == -1) continue; /* try next field */ - 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); - 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); - MSG("INFO: [down] result %i host:%s service:%s\n", i, host_name, port_name); - ++i; - } - exit(EXIT_FAILURE); - } - - /* connect so we can send/receive packet with the server only */ - i = connect(sock_down, q->ai_addr, q->ai_addrlen); - if (i != 0) { - MSG("ERROR: [down] connect returned %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - 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); - } - - for (l = 0; l < LGW_IF_CHAIN_NB; l++) { - for (m = 0; m < 8; m++) { - nb_pkt_log[l][m] = 0; - } - } - - /* starting the concentrator */ - i = lgw_start(); - if (i == LGW_HAL_SUCCESS) { - MSG("INFO: [main] concentrator started, packet can now be received\n"); - } else { - MSG("ERROR: [main] failed to start the concentrator\n"); - exit(EXIT_FAILURE); - } - - /* get the concentrator EUI */ - i = lgw_get_eui(&eui); - if (i != LGW_HAL_SUCCESS) { - printf("ERROR: failed to get concentrator EUI\n"); - } else { - printf("INFO: concentrator EUI: 0x%016" PRIx64 "\n", eui); - } - - /* spawn threads to manage upstream and downstream */ - 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); - 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); - if (i != 0) { - MSG("ERROR: [main] impossible to create JIT 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); - 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); - if (i != 0) { - MSG("ERROR: [main] impossible to create validation thread\n"); - exit(EXIT_FAILURE); - } - } - - /* configure signal handling */ - sigemptyset(&sigact.sa_mask); - sigact.sa_flags = 0; - sigact.sa_handler = sig_handler; - sigaction(SIGQUIT, &sigact, NULL); /* Ctrl-\ */ - sigaction(SIGINT, &sigact, NULL); /* Ctrl-C */ - sigaction(SIGTERM, &sigact, NULL); /* default "kill" command */ - - /* main loop task : statistics collection */ - while (!exit_sig && !quit_sig) { - /* wait for next reporting interval */ - wait_ms(1000 * stat_interval); - - /* get timestamp for statistics */ - t = time(NULL); - strftime(stat_timestamp, sizeof stat_timestamp, "%F %T %Z", gmtime(&t)); - - /* access upstream statistics, copy and reset them */ - pthread_mutex_lock(&mx_meas_up); - cp_nb_rx_rcv = meas_nb_rx_rcv; - cp_nb_rx_ok = meas_nb_rx_ok; - cp_nb_rx_bad = meas_nb_rx_bad; - cp_nb_rx_nocrc = meas_nb_rx_nocrc; - cp_up_pkt_fwd = meas_up_pkt_fwd; - cp_up_network_byte = meas_up_network_byte; - cp_up_payload_byte = meas_up_payload_byte; - cp_up_dgram_sent = meas_up_dgram_sent; - cp_up_ack_rcv = meas_up_ack_rcv; - meas_nb_rx_rcv = 0; - meas_nb_rx_ok = 0; - meas_nb_rx_bad = 0; - meas_nb_rx_nocrc = 0; - meas_up_pkt_fwd = 0; - meas_up_network_byte = 0; - meas_up_payload_byte = 0; - meas_up_dgram_sent = 0; - meas_up_ack_rcv = 0; - pthread_mutex_unlock(&mx_meas_up); - if (cp_nb_rx_rcv > 0) { - rx_ok_ratio = (float)cp_nb_rx_ok / (float)cp_nb_rx_rcv; - rx_bad_ratio = (float)cp_nb_rx_bad / (float)cp_nb_rx_rcv; - rx_nocrc_ratio = (float)cp_nb_rx_nocrc / (float)cp_nb_rx_rcv; - } else { - rx_ok_ratio = 0.0; - rx_bad_ratio = 0.0; - rx_nocrc_ratio = 0.0; - } - if (cp_up_dgram_sent > 0) { - up_ack_ratio = (float)cp_up_ack_rcv / (float)cp_up_dgram_sent; - } else { - up_ack_ratio = 0.0; - } - - /* access downstream statistics, copy and reset them */ - pthread_mutex_lock(&mx_meas_dw); - cp_dw_pull_sent = meas_dw_pull_sent; - cp_dw_ack_rcv = meas_dw_ack_rcv; - cp_dw_dgram_rcv = meas_dw_dgram_rcv; - cp_dw_network_byte = meas_dw_network_byte; - cp_dw_payload_byte = meas_dw_payload_byte; - cp_nb_tx_ok = meas_nb_tx_ok; - cp_nb_tx_fail = meas_nb_tx_fail; - cp_nb_tx_requested += meas_nb_tx_requested; - cp_nb_tx_rejected_collision_packet += meas_nb_tx_rejected_collision_packet; - cp_nb_tx_rejected_collision_beacon += meas_nb_tx_rejected_collision_beacon; - cp_nb_tx_rejected_too_late += meas_nb_tx_rejected_too_late; - cp_nb_tx_rejected_too_early += meas_nb_tx_rejected_too_early; - cp_nb_beacon_queued += meas_nb_beacon_queued; - cp_nb_beacon_sent += meas_nb_beacon_sent; - cp_nb_beacon_rejected += meas_nb_beacon_rejected; - meas_dw_pull_sent = 0; - meas_dw_ack_rcv = 0; - meas_dw_dgram_rcv = 0; - meas_dw_network_byte = 0; - meas_dw_payload_byte = 0; - meas_nb_tx_ok = 0; - meas_nb_tx_fail = 0; - meas_nb_tx_requested = 0; - meas_nb_tx_rejected_collision_packet = 0; - meas_nb_tx_rejected_collision_beacon = 0; - meas_nb_tx_rejected_too_late = 0; - meas_nb_tx_rejected_too_early = 0; - meas_nb_beacon_queued = 0; - meas_nb_beacon_sent = 0; - meas_nb_beacon_rejected = 0; - pthread_mutex_unlock(&mx_meas_dw); - if (cp_dw_pull_sent > 0) { - dw_ack_ratio = (float)cp_dw_ack_rcv / (float)cp_dw_pull_sent; - } else { - dw_ack_ratio = 0.0; - } - - /* access GPS statistics, copy them */ - if (gps_enabled == true) { - pthread_mutex_lock(&mx_meas_gps); - coord_ok = gps_coord_valid; - cp_gps_coord = meas_gps_coord; - pthread_mutex_unlock(&mx_meas_gps); - } - - /* overwrite with reference coordinates if function is enabled */ - if (gps_fake_enable == true) { - cp_gps_coord = reference_coord; - } - - /* display a report */ - printf("\n##### %s #####\n", stat_timestamp); - printf("### [UPSTREAM] ###\n"); - printf("# RF packets received by concentrator: %u\n", cp_nb_rx_rcv); - printf("# CRC_OK: %.2f%%, CRC_FAIL: %.2f%%, NO_CRC: %.2f%%\n", 100.0 * rx_ok_ratio, 100.0 * rx_bad_ratio, 100.0 * rx_nocrc_ratio); - printf("# RF packets forwarded: %u (%u bytes)\n", cp_up_pkt_fwd, cp_up_payload_byte); - printf("# PUSH_DATA datagrams sent: %u (%u bytes)\n", cp_up_dgram_sent, cp_up_network_byte); - printf("# PUSH_DATA acknowledged: %.2f%%\n", 100.0 * up_ack_ratio); - printf("### [DOWNSTREAM] ###\n"); - printf("# PULL_DATA sent: %u (%.2f%% acknowledged)\n", cp_dw_pull_sent, 100.0 * dw_ack_ratio); - printf("# PULL_RESP(onse) datagrams received: %u (%u bytes)\n", cp_dw_dgram_rcv, cp_dw_network_byte); - printf("# RF packets sent to concentrator: %u (%u bytes)\n", (cp_nb_tx_ok+cp_nb_tx_fail), cp_dw_payload_byte); - printf("# TX errors: %u\n", cp_nb_tx_fail); - if (cp_nb_tx_requested != 0 ) { - printf("# TX rejected (collision packet): %.2f%% (req:%u, rej:%u)\n", 100.0 * cp_nb_tx_rejected_collision_packet / cp_nb_tx_requested, cp_nb_tx_requested, cp_nb_tx_rejected_collision_packet); - printf("# TX rejected (collision beacon): %.2f%% (req:%u, rej:%u)\n", 100.0 * cp_nb_tx_rejected_collision_beacon / cp_nb_tx_requested, cp_nb_tx_requested, cp_nb_tx_rejected_collision_beacon); - printf("# TX rejected (too late): %.2f%% (req:%u, rej:%u)\n", 100.0 * cp_nb_tx_rejected_too_late / cp_nb_tx_requested, cp_nb_tx_requested, cp_nb_tx_rejected_too_late); - printf("# TX rejected (too early): %.2f%% (req:%u, rej:%u)\n", 100.0 * cp_nb_tx_rejected_too_early / cp_nb_tx_requested, cp_nb_tx_requested, cp_nb_tx_rejected_too_early); - } - printf("### SX1302 Status ###\n"); - pthread_mutex_lock(&mx_concent); - i = lgw_get_instcnt(&inst_tstamp); - i |= lgw_get_trigcnt(&trig_tstamp); - pthread_mutex_unlock(&mx_concent); - if (i != LGW_HAL_SUCCESS) { - printf("# SX1302 counter unknown\n"); - } else { - printf("# SX1302 counter (INST): %u\n", inst_tstamp); - printf("# SX1302 counter (PPS): %u\n", trig_tstamp); - } - printf("# BEACON queued: %u\n", cp_nb_beacon_queued); - printf("# BEACON sent so far: %u\n", cp_nb_beacon_sent); - printf("# BEACON rejected: %u\n", cp_nb_beacon_rejected); - printf("### [JIT] ###\n"); - /* get timestamp captured on PPM pulse */ - jit_print_queue (&jit_queue[0], false, DEBUG_LOG); - printf("#--------\n"); - jit_print_queue (&jit_queue[1], false, DEBUG_LOG); - printf("### [GPS] ###\n"); - if (gps_enabled == true) { - /* no need for mutex, display is not critical */ - if (gps_ref_valid == true) { - printf("# Valid time reference (age: %li sec)\n", (long)difftime(time(NULL), time_reference_gps.systime)); - } else { - printf("# Invalid time reference (age: %li sec)\n", (long)difftime(time(NULL), time_reference_gps.systime)); - } - if (coord_ok == true) { - printf("# GPS coordinates: latitude %.5f, longitude %.5f, altitude %i m\n", cp_gps_coord.lat, cp_gps_coord.lon, cp_gps_coord.alt); - } else { - printf("# no valid GPS coordinates available yet\n"); - } - } else if (gps_fake_enable == true) { - printf("# GPS *FAKE* coordinates: latitude %.5f, longitude %.5f, altitude %i m\n", cp_gps_coord.lat, cp_gps_coord.lon, cp_gps_coord.alt); - } else { - printf("# GPS sync is disabled\n"); - } - /* - i = lgw_get_temperature(&temperature); - if (i != LGW_HAL_SUCCESS) { - printf("### Concentrator temperature unknown ###\n"); - } else { - 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); - } 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); - } - 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 */ - if (gps_enabled == true) { - pthread_cancel(thrid_gps); /* don't wait for GPS thread */ - pthread_cancel(thrid_valid); /* don't wait for validation thread */ - - i = lgw_gps_disable(gps_tty_fd); - if (i == LGW_HAL_SUCCESS) { - MSG("INFO: GPS closed successfully\n"); - } else { - MSG("WARNING: failed to close GPS successfully\n"); - } - } - - /* if an exit signal was received, try to quit properly */ - if (exit_sig) { - /* shut down network sockets */ - shutdown(sock_up, SHUT_RDWR); - shutdown(sock_down, SHUT_RDWR); - /* stop the hardware */ - i = lgw_stop(); - if (i == LGW_HAL_SUCCESS) { - MSG("INFO: concentrator stopped successfully\n"); - } else { - MSG("WARNING: failed to stop concentrator successfully\n"); - } - } - - /* 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"); - exit(EXIT_SUCCESS); -} - -/* -------------------------------------------------------------------------- */ -/* --- THREAD 1: RECEIVING PACKETS AND FORWARDING THEM ---------------------- */ - -void thread_up(void) { - int i, j, k; /* loop variables */ - unsigned pkt_in_dgram; /* nb on Lora packet in the current datagram */ - char stat_timestamp[24]; - time_t t; - - /* allocate memory for packet fetching and processing */ - struct lgw_pkt_rx_s rxpkt[NB_PKT_MAX]; /* array containing inbound packets + metadata */ - struct lgw_pkt_rx_s *p; /* pointer on a RX packet */ - int nb_pkt; - - /* local copy of GPS time reference */ - bool ref_ok = false; /* determine if GPS time reference must be used or not */ - struct tref local_ref; /* time reference used for UTC <-> timestamp conversion */ - - /* data buffers */ - uint8_t buff_up[TX_BUFF_SIZE]; /* buffer to compose the upstream packet */ - int buff_index; - uint8_t buff_ack[32]; /* buffer to receive acknowledges */ - - /* protocol variables */ - uint8_t token_h; /* random token for acknowledgement matching */ - uint8_t token_l; /* random token for acknowledgement matching */ - - /* ping measurement variables */ - struct timespec send_time; - struct timespec recv_time; - - /* GPS synchronization variables */ - struct timespec pkt_utc_time; - struct tm * x; /* broken-up UTC time */ - struct timespec pkt_gps_time; - uint64_t pkt_gps_time_ms; - - /* report management variable */ - bool send_report = false; - - /* mote info variables */ - uint32_t mote_addr = 0; - uint16_t mote_fcnt = 0; - - /* set upstream socket RX timeout */ - i = setsockopt(sock_up, SOL_SOCKET, SO_RCVTIMEO, (void *)&push_timeout_half, sizeof push_timeout_half); - if (i != 0) { - MSG("ERROR: [up] setsockopt returned %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - - /* pre-fill the data buffer with fixed fields */ - buff_up[0] = PROTOCOL_VERSION; - buff_up[3] = PKT_PUSH_DATA; - *(uint32_t *)(buff_up + 4) = net_mac_h; - *(uint32_t *)(buff_up + 8) = net_mac_l; - - while (!exit_sig && !quit_sig) { - - /* fetch packets */ - pthread_mutex_lock(&mx_concent); - nb_pkt = lgw_receive(NB_PKT_MAX, rxpkt); - pthread_mutex_unlock(&mx_concent); - if (nb_pkt == LGW_HAL_ERROR) { - MSG("ERROR: [up] failed packet fetch, exiting\n"); - exit(EXIT_FAILURE); - } - - /* check if there are status report to send */ - send_report = report_ready; /* copy the variable so it doesn't change mid-function */ - /* no mutex, we're only reading */ - - /* wait a short time if no packets, nor status report */ - if ((nb_pkt == 0) && (send_report == false)) { - wait_ms(FETCH_SLEEP_MS); - continue; - } - - /* get a copy of GPS time reference (avoid 1 mutex per packet) */ - if ((nb_pkt > 0) && (gps_enabled == true)) { - pthread_mutex_lock(&mx_timeref); - ref_ok = gps_ref_valid; - local_ref = time_reference_gps; - pthread_mutex_unlock(&mx_timeref); - } else { - ref_ok = false; - } - - /* get timestamp for statistics */ - t = time(NULL); - strftime(stat_timestamp, sizeof stat_timestamp, "%F %T %Z", gmtime(&t)); - MSG_DEBUG(DEBUG_PKT_FWD, "\nCurrent time: %s \n", stat_timestamp); - - /* start composing datagram with the header */ - token_h = (uint8_t)rand(); /* random token */ - token_l = (uint8_t)rand(); /* random token */ - buff_up[1] = token_h; - buff_up[2] = token_l; - buff_index = 12; /* 12-byte header */ - - /* start of JSON structure */ - memcpy((void *)(buff_up + buff_index), (void *)"{\"rxpk\":[", 9); - buff_index += 9; - - /* serialize Lora packets metadata and payload */ - pkt_in_dgram = 0; - for (i = 0; i < nb_pkt; ++i) { - p = &rxpkt[i]; - - /* Get mote information from current packet (addr, fcnt) */ - /* FHDR - DevAddr */ - if (p->size >= 8) { - mote_addr = p->payload[1]; - mote_addr |= p->payload[2] << 8; - mote_addr |= p->payload[3] << 16; - mote_addr |= p->payload[4] << 24; - /* FHDR - FCnt */ - mote_fcnt = p->payload[6]; - mote_fcnt |= p->payload[7] << 8; - } else { - mote_addr = 0; - mote_fcnt = 0; - } - - /* basic packet filtering */ - pthread_mutex_lock(&mx_meas_up); - meas_nb_rx_rcv += 1; - switch(p->status) { - case STAT_CRC_OK: - meas_nb_rx_ok += 1; - if (!fwd_valid_pkt) { - pthread_mutex_unlock(&mx_meas_up); - continue; /* skip that packet */ - } - break; - case STAT_CRC_BAD: - meas_nb_rx_bad += 1; - if (!fwd_error_pkt) { - pthread_mutex_unlock(&mx_meas_up); - continue; /* skip that packet */ - } - break; - case STAT_NO_CRC: - meas_nb_rx_nocrc += 1; - if (!fwd_nocrc_pkt) { - pthread_mutex_unlock(&mx_meas_up); - continue; /* skip that packet */ - } - break; - default: - MSG("WARNING: [up] received packet with unknown status %u (size %u, modulation %u, BW %u, DR %u, RSSI %.1f)\n", p->status, p->size, p->modulation, p->bandwidth, p->datarate, p->rssic); - pthread_mutex_unlock(&mx_meas_up); - continue; /* skip that packet */ - // exit(EXIT_FAILURE); - } - meas_up_pkt_fwd += 1; - meas_up_payload_byte += p->size; - pthread_mutex_unlock(&mx_meas_up); - printf( "\nINFO: Received pkt from mote: %08X (fcnt=%u)\n", mote_addr, mote_fcnt ); - - /* Start of packet, add inter-packet separator if necessary */ - if (pkt_in_dgram == 0) { - buff_up[buff_index] = '{'; - ++buff_index; - } else { - buff_up[buff_index] = ','; - buff_up[buff_index+1] = '{'; - buff_index += 2; - } - - /* JSON rxpk frame format version, 8 useful chars */ - j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, "\"jver\":%d", PROTOCOL_JSON_RXPK_FRAME_FORMAT ); - if (j > 0) { - buff_index += j; - } else { - MSG("ERROR: [up] snprintf failed line %u\n", (__LINE__ - 4)); - exit(EXIT_FAILURE); - } - - /* RAW timestamp, 8-17 useful chars */ - j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, ",\"tmst\":%u", p->count_us); - if (j > 0) { - buff_index += j; - } else { - MSG("ERROR: [up] snprintf failed line %u\n", (__LINE__ - 4)); - exit(EXIT_FAILURE); - } - - /* Packet RX time (GPS based), 37 useful chars */ - if (ref_ok == true) { - /* convert packet timestamp to UTC absolute time */ - j = lgw_cnt2utc(local_ref, p->count_us, &pkt_utc_time); - if (j == LGW_GPS_SUCCESS) { - /* split the UNIX timestamp to its calendar components */ - x = gmtime(&(pkt_utc_time.tv_sec)); - j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, ",\"time\":\"%04i-%02i-%02iT%02i:%02i:%02i.%06liZ\"", (x->tm_year)+1900, (x->tm_mon)+1, x->tm_mday, x->tm_hour, x->tm_min, x->tm_sec, (pkt_utc_time.tv_nsec)/1000); /* ISO 8601 format */ - if (j > 0) { - buff_index += j; - } else { - MSG("ERROR: [up] snprintf failed line %u\n", (__LINE__ - 4)); - exit(EXIT_FAILURE); - } - } - /* convert packet timestamp to GPS absolute time */ - j = lgw_cnt2gps(local_ref, p->count_us, &pkt_gps_time); - if (j == LGW_GPS_SUCCESS) { - pkt_gps_time_ms = pkt_gps_time.tv_sec * 1E3 + pkt_gps_time.tv_nsec / 1E6; - j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, ",\"tmms\":%" PRIu64 "", pkt_gps_time_ms); /* GPS time in milliseconds since 06.Jan.1980 */ - 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) { - buff_index += j; - } else { - MSG("ERROR: [up] snprintf failed line %u\n", (__LINE__ - 4)); - exit(EXIT_FAILURE); - } - - /* Packet status, 9-10 useful chars */ - switch (p->status) { - case STAT_CRC_OK: - memcpy((void *)(buff_up + buff_index), (void *)",\"stat\":1", 9); - buff_index += 9; - break; - case STAT_CRC_BAD: - memcpy((void *)(buff_up + buff_index), (void *)",\"stat\":-1", 10); - buff_index += 10; - break; - case STAT_NO_CRC: - memcpy((void *)(buff_up + buff_index), (void *)",\"stat\":0", 9); - buff_index += 9; - break; - default: - MSG("ERROR: [up] received packet with unknown status 0x%02X\n", p->status); - memcpy((void *)(buff_up + buff_index), (void *)",\"stat\":?", 9); - buff_index += 9; - exit(EXIT_FAILURE); - } - - /* Packet modulation, 13-14 useful chars */ - if (p->modulation == MOD_LORA) { - memcpy((void *)(buff_up + buff_index), (void *)",\"modu\":\"LORA\"", 14); - buff_index += 14; - - /* Lora datarate & bandwidth, 16-19 useful chars */ - switch (p->datarate) { - case DR_LORA_SF5: - memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF5", 12); - buff_index += 12; - break; - case DR_LORA_SF6: - memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF6", 12); - buff_index += 12; - break; - case DR_LORA_SF7: - memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF7", 12); - buff_index += 12; - break; - case DR_LORA_SF8: - memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF8", 12); - buff_index += 12; - break; - case DR_LORA_SF9: - memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF9", 12); - buff_index += 12; - break; - case DR_LORA_SF10: - memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF10", 13); - buff_index += 13; - break; - case DR_LORA_SF11: - memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF11", 13); - buff_index += 13; - break; - case DR_LORA_SF12: - memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF12", 13); - buff_index += 13; - break; - default: - MSG("ERROR: [up] lora packet with unknown datarate 0x%02X\n", p->datarate); - memcpy((void *)(buff_up + buff_index), (void *)",\"datr\":\"SF?", 12); - buff_index += 12; - exit(EXIT_FAILURE); - } - switch (p->bandwidth) { - case BW_125KHZ: - memcpy((void *)(buff_up + buff_index), (void *)"BW125\"", 6); - buff_index += 6; - break; - case BW_250KHZ: - memcpy((void *)(buff_up + buff_index), (void *)"BW250\"", 6); - buff_index += 6; - break; - case BW_500KHZ: - memcpy((void *)(buff_up + buff_index), (void *)"BW500\"", 6); - buff_index += 6; - break; - default: - MSG("ERROR: [up] lora packet with unknown bandwidth 0x%02X\n", p->bandwidth); - memcpy((void *)(buff_up + buff_index), (void *)"BW?\"", 4); - buff_index += 4; - exit(EXIT_FAILURE); - } - - /* Packet ECC coding rate, 11-13 useful chars */ - switch (p->coderate) { - case CR_LORA_4_5: - memcpy((void *)(buff_up + buff_index), (void *)",\"codr\":\"4/5\"", 13); - buff_index += 13; - break; - case CR_LORA_4_6: - memcpy((void *)(buff_up + buff_index), (void *)",\"codr\":\"4/6\"", 13); - buff_index += 13; - break; - case CR_LORA_4_7: - memcpy((void *)(buff_up + buff_index), (void *)",\"codr\":\"4/7\"", 13); - buff_index += 13; - break; - case CR_LORA_4_8: - memcpy((void *)(buff_up + buff_index), (void *)",\"codr\":\"4/8\"", 13); - buff_index += 13; - break; - case 0: /* treat the CR0 case (mostly false sync) */ - memcpy((void *)(buff_up + buff_index), (void *)",\"codr\":\"OFF\"", 13); - buff_index += 13; - break; - default: - MSG("ERROR: [up] lora packet with unknown coderate 0x%02X\n", p->coderate); - memcpy((void *)(buff_up + buff_index), (void *)",\"codr\":\"?\"", 11); - buff_index += 11; - exit(EXIT_FAILURE); - } - - /* Signal RSSI, payload size */ - j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, ",\"rssis\":%.0f", roundf(p->rssis)); - if (j > 0) { - buff_index += j; - } else { - MSG("ERROR: [up] snprintf failed line %u\n", (__LINE__ - 4)); - exit(EXIT_FAILURE); - } - - /* Lora SNR */ - j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, ",\"lsnr\":%.1f", p->snr); - if (j > 0) { - buff_index += j; - } else { - MSG("ERROR: [up] snprintf failed line %u\n", (__LINE__ - 4)); - exit(EXIT_FAILURE); - } - - /* Lora frequency offset */ - j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, ",\"foff\":%d", p->freq_offset); - if (j > 0) { - buff_index += j; - } else { - MSG("ERROR: [up] snprintf failed line %u\n", (__LINE__ - 4)); - exit(EXIT_FAILURE); - } - } else if (p->modulation == MOD_FSK) { - memcpy((void *)(buff_up + buff_index), (void *)",\"modu\":\"FSK\"", 13); - buff_index += 13; - - /* FSK datarate, 11-14 useful chars */ - j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, ",\"datr\":%u", p->datarate); - if (j > 0) { - buff_index += j; - } else { - MSG("ERROR: [up] snprintf failed line %u\n", (__LINE__ - 4)); - exit(EXIT_FAILURE); - } - } else { - MSG("ERROR: [up] received packet with unknown modulation 0x%02X\n", p->modulation); - exit(EXIT_FAILURE); - } - - /* Channel RSSI, payload size, 18-23 useful chars */ - j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, ",\"rssi\":%.0f,\"size\":%u", roundf(p->rssic), p->size); - if (j > 0) { - buff_index += j; - } else { - MSG("ERROR: [up] snprintf failed line %u\n", (__LINE__ - 4)); - exit(EXIT_FAILURE); - } - - /* Packet base64-encoded payload, 14-350 useful chars */ - memcpy((void *)(buff_up + buff_index), (void *)",\"data\":\"", 9); - buff_index += 9; - j = bin_to_b64(p->payload, p->size, (char *)(buff_up + buff_index), 341); /* 255 bytes = 340 chars in b64 + null char */ - if (j>=0) { - buff_index += j; - } else { - MSG("ERROR: [up] bin_to_b64 failed line %u\n", (__LINE__ - 5)); - exit(EXIT_FAILURE); - } - buff_up[buff_index] = '"'; - ++buff_index; - - /* End of packet serialization */ - buff_up[buff_index] = '}'; - ++buff_index; - ++pkt_in_dgram; - - if (p->modulation == MOD_LORA) { - /* Log nb of packets per channel, per SF */ - nb_pkt_log[p->if_chain][p->datarate - 5] += 1; - nb_pkt_received_lora += 1; - - /* Log nb of packets for ref_payload (DEBUG) */ - for (k = 0; k < debugconf.nb_ref_payload; k++) { - if ((p->payload[0] == (uint8_t)(debugconf.ref_payload[k].id >> 24)) && - (p->payload[1] == (uint8_t)(debugconf.ref_payload[k].id >> 16)) && - (p->payload[2] == (uint8_t)(debugconf.ref_payload[k].id >> 8)) && - (p->payload[3] == (uint8_t)(debugconf.ref_payload[k].id >> 0))) { - nb_pkt_received_ref[k] += 1; - } - } - } else if (p->modulation == MOD_FSK) { - nb_pkt_log[p->if_chain][0] += 1; - nb_pkt_received_fsk += 1; - } - } - - - /* DEBUG: print the number of packets received per channel and per SF */ - { - int l, m; - MSG_PRINTF(DEBUG_PKT_FWD, "\n"); - for (l = 0; l < (LGW_IF_CHAIN_NB - 1); l++) { - MSG_PRINTF(DEBUG_PKT_FWD, "CH%d: ", l); - for (m = 0; m < 8; m++) { - MSG_PRINTF(DEBUG_PKT_FWD, "\t%d", nb_pkt_log[l][m]); - } - MSG_PRINTF(DEBUG_PKT_FWD, "\n"); - } - MSG_PRINTF(DEBUG_PKT_FWD, "FSK: \t%d", nb_pkt_log[9][0]); - MSG_PRINTF(DEBUG_PKT_FWD, "\n"); - MSG_PRINTF(DEBUG_PKT_FWD, "Total number of LoRa packet received: %u\n", nb_pkt_received_lora); - MSG_PRINTF(DEBUG_PKT_FWD, "Total number of FSK packet received: %u\n", nb_pkt_received_fsk); - for (l = 0; l < debugconf.nb_ref_payload; l++) { - MSG_PRINTF(DEBUG_PKT_FWD, "Total number of LoRa packet received from 0x%08X: %u\n", debugconf.ref_payload[l].id, nb_pkt_received_ref[l]); - } - } - - /* restart fetch sequence without sending empty JSON if all packets have been filtered out */ - if (pkt_in_dgram == 0) { - if (send_report == true) { - /* need to clean up the beginning of the payload */ - buff_index -= 8; /* removes "rxpk":[ */ - } else { - /* all packet have been filtered out and no report, restart loop */ - continue; - } - } else { - /* end of packet array */ - buff_up[buff_index] = ']'; - ++buff_index; - /* add separator if needed */ - if (send_report == true) { - buff_up[buff_index] = ','; - ++buff_index; - } - } - - /* add status report if a new one is available */ - if (send_report == true) { - pthread_mutex_lock(&mx_stat_rep); - report_ready = false; - j = snprintf((char *)(buff_up + buff_index), TX_BUFF_SIZE-buff_index, "%s", status_report); - pthread_mutex_unlock(&mx_stat_rep); - if (j > 0) { - buff_index += j; - } else { - MSG("ERROR: [up] snprintf failed line %u\n", (__LINE__ - 5)); - exit(EXIT_FAILURE); - } - } - - /* end of JSON datagram payload */ - buff_up[buff_index] = '}'; - ++buff_index; - buff_up[buff_index] = 0; /* add string terminator, for safety */ - - printf("\nJSON up: %s\n", (char *)(buff_up + 12)); /* DEBUG: display JSON payload */ - - /* send datagram to server */ - send(sock_up, (void *)buff_up, buff_index, 0); - clock_gettime(CLOCK_MONOTONIC, &send_time); - pthread_mutex_lock(&mx_meas_up); - meas_up_dgram_sent += 1; - meas_up_network_byte += buff_index; - - /* wait for acknowledge (in 2 times, to catch extra packets) */ - for (i=0; i<2; ++i) { - j = recv(sock_up, (void *)buff_ack, sizeof buff_ack, 0); - clock_gettime(CLOCK_MONOTONIC, &recv_time); - if (j == -1) { - if (errno == EAGAIN) { /* timeout */ - continue; - } else { /* server connection error */ - break; - } - } else if ((j < 4) || (buff_ack[0] != PROTOCOL_VERSION) || (buff_ack[3] != PKT_PUSH_ACK)) { - //MSG("WARNING: [up] ignored invalid non-ACL packet\n"); - continue; - } else if ((buff_ack[1] != token_h) || (buff_ack[2] != token_l)) { - //MSG("WARNING: [up] ignored out-of sync ACK packet\n"); - continue; - } else { - MSG("INFO: [up] PUSH_ACK received in %i ms\n", (int)(1000 * difftimespec(recv_time, send_time))); - meas_up_ack_rcv += 1; - break; - } - } - pthread_mutex_unlock(&mx_meas_up); - } - MSG("\nINFO: End of upstream thread\n"); -} - -/* -------------------------------------------------------------------------- */ -/* --- THREAD 2: POLLING SERVER AND ENQUEUING PACKETS IN JIT QUEUE ---------- */ - -static int get_tx_gain_lut_index(uint8_t rf_chain, int8_t rf_power, uint8_t * lut_index) { - uint8_t pow_index; - int current_best_index = -1; - uint8_t current_best_match = 0xFF; - int diff; - - /* Check input parameters */ - if (lut_index == NULL) { - MSG("ERROR: %s - wrong parameter\n", __FUNCTION__); - return -1; - } - - /* Search requested power in TX gain LUT */ - for (pow_index = 0; pow_index < txlut[rf_chain].size; pow_index++) { - diff = rf_power - txlut[rf_chain].lut[pow_index].rf_power; - if (diff < 0) { - /* The selected power must be lower or equal to requested one */ - continue; - } else { - /* Record the index corresponding to the closest rf_power available in LUT */ - if ((current_best_index == -1) || (diff < current_best_match)) { - current_best_match = diff; - current_best_index = pow_index; - } - } - } - - /* Return corresponding index */ - if (current_best_index > -1) { - *lut_index = (uint8_t)current_best_index; - } else { - *lut_index = 0; - MSG("ERROR: %s - failed to find tx gain lut index\n", __FUNCTION__); - return -1; - } - - return 0; -} - -void thread_down(void) { - int i; /* loop variables */ - - /* configuration and metadata for an outbound packet */ - struct lgw_pkt_tx_s txpkt; - bool sent_immediate = false; /* option to sent the packet immediately */ - - /* local timekeeping variables */ - struct timespec send_time; /* time of the pull request */ - struct timespec recv_time; /* time of return from recv socket call */ - - /* data buffers */ - uint8_t buff_down[1000]; /* buffer to receive downstream packets */ - uint8_t buff_req[12]; /* buffer to compose pull requests */ - int msg_len; - - /* protocol variables */ - uint8_t token_h; /* random token for acknowledgement matching */ - uint8_t token_l; /* random token for acknowledgement matching */ - bool req_ack = false; /* keep track of whether PULL_DATA was acknowledged or not */ - - /* JSON parsing variables */ - JSON_Value *root_val = NULL; - JSON_Object *txpk_obj = NULL; - JSON_Value *val = NULL; /* needed to detect the absence of some fields */ - const char *str; /* pointer to sub-strings in the JSON data */ - short x0, x1; - uint64_t x2; - double x3, x4; - - /* variables to send on GPS timestamp */ - struct tref local_ref; /* time reference used for GPS <-> timestamp conversion */ - struct timespec gps_tx; /* GPS time that needs to be converted to timestamp */ - - /* beacon variables */ - struct lgw_pkt_tx_s beacon_pkt; - uint8_t beacon_chan; - uint8_t beacon_loop; - size_t beacon_RFU1_size = 0; - size_t beacon_RFU2_size = 0; - uint8_t beacon_pyld_idx = 0; - time_t diff_beacon_time; - struct timespec next_beacon_gps_time; /* gps time of next beacon packet */ - struct timespec last_beacon_gps_time; /* gps time of last enqueued beacon packet */ - int retry; - - /* beacon data fields, byte 0 is Least Significant Byte */ - int32_t field_latitude; /* 3 bytes, derived from reference latitude */ - int32_t field_longitude; /* 3 bytes, derived from reference longitude */ - uint16_t field_crc1, field_crc2; - - /* auto-quit variable */ - uint32_t autoquit_cnt = 0; /* count the number of PULL_DATA sent since the latest PULL_ACK */ - - /* Just In Time downlink */ - uint32_t current_concentrator_time; - enum jit_error_e jit_result = JIT_ERROR_OK; - enum jit_pkt_type_e downlink_type; - enum jit_error_e warning_result = JIT_ERROR_OK; - int32_t warning_value = 0; - uint8_t tx_lut_idx = 0; - - /* set downstream socket RX timeout */ - i = setsockopt(sock_down, SOL_SOCKET, SO_RCVTIMEO, (void *)&pull_timeout, sizeof pull_timeout); - if (i != 0) { - MSG("ERROR: [down] setsockopt returned %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } - - /* pre-fill the pull request buffer with fixed fields */ - buff_req[0] = PROTOCOL_VERSION; - buff_req[3] = PKT_PULL_DATA; - *(uint32_t *)(buff_req + 4) = net_mac_h; - *(uint32_t *)(buff_req + 8) = net_mac_l; - - /* beacon variables initialization */ - last_beacon_gps_time.tv_sec = 0; - last_beacon_gps_time.tv_nsec = 0; - - /* beacon packet parameters */ - beacon_pkt.tx_mode = ON_GPS; /* send on PPS pulse */ - beacon_pkt.rf_chain = 0; /* antenna A */ - beacon_pkt.rf_power = beacon_power; - beacon_pkt.modulation = MOD_LORA; - switch (beacon_bw_hz) { - case 125000: - beacon_pkt.bandwidth = BW_125KHZ; - break; - case 500000: - beacon_pkt.bandwidth = BW_500KHZ; - break; - default: - /* should not happen */ - MSG("ERROR: unsupported bandwidth for beacon\n"); - exit(EXIT_FAILURE); - } - switch (beacon_datarate) { - case 8: - beacon_pkt.datarate = DR_LORA_SF8; - beacon_RFU1_size = 1; - beacon_RFU2_size = 3; - break; - case 9: - beacon_pkt.datarate = DR_LORA_SF9; - beacon_RFU1_size = 2; - beacon_RFU2_size = 0; - break; - case 10: - beacon_pkt.datarate = DR_LORA_SF10; - beacon_RFU1_size = 3; - beacon_RFU2_size = 1; - break; - case 12: - beacon_pkt.datarate = DR_LORA_SF12; - beacon_RFU1_size = 5; - beacon_RFU2_size = 3; - break; - default: - /* should not happen */ - MSG("ERROR: unsupported datarate for beacon\n"); - exit(EXIT_FAILURE); - } - beacon_pkt.size = beacon_RFU1_size + 4 + 2 + 7 + beacon_RFU2_size + 2; - beacon_pkt.coderate = CR_LORA_4_5; - beacon_pkt.invert_pol = false; - beacon_pkt.preamble = 10; - beacon_pkt.no_crc = true; - beacon_pkt.no_header = true; - - /* network common part beacon fields (little endian) */ - for (i = 0; i < (int)beacon_RFU1_size; i++) { - beacon_pkt.payload[beacon_pyld_idx++] = 0x0; - } - - /* network common part beacon fields (little endian) */ - beacon_pyld_idx += 4; /* time (variable), filled later */ - beacon_pyld_idx += 2; /* crc1 (variable), filled later */ - - /* calculate the latitude and longitude that must be publicly reported */ - field_latitude = (int32_t)((reference_coord.lat / 90.0) * (double)(1<<23)); - if (field_latitude > (int32_t)0x007FFFFF) { - field_latitude = (int32_t)0x007FFFFF; /* +90 N is represented as 89.99999 N */ - } else if (field_latitude < (int32_t)0xFF800000) { - field_latitude = (int32_t)0xFF800000; - } - field_longitude = (int32_t)((reference_coord.lon / 180.0) * (double)(1<<23)); - if (field_longitude > (int32_t)0x007FFFFF) { - field_longitude = (int32_t)0x007FFFFF; /* +180 E is represented as 179.99999 E */ - } else if (field_longitude < (int32_t)0xFF800000) { - field_longitude = (int32_t)0xFF800000; - } - - /* gateway specific beacon fields */ - beacon_pkt.payload[beacon_pyld_idx++] = beacon_infodesc; - beacon_pkt.payload[beacon_pyld_idx++] = 0xFF & field_latitude; - beacon_pkt.payload[beacon_pyld_idx++] = 0xFF & (field_latitude >> 8); - beacon_pkt.payload[beacon_pyld_idx++] = 0xFF & (field_latitude >> 16); - beacon_pkt.payload[beacon_pyld_idx++] = 0xFF & field_longitude; - beacon_pkt.payload[beacon_pyld_idx++] = 0xFF & (field_longitude >> 8); - beacon_pkt.payload[beacon_pyld_idx++] = 0xFF & (field_longitude >> 16); - - /* RFU */ - for (i = 0; i < (int)beacon_RFU2_size; i++) { - beacon_pkt.payload[beacon_pyld_idx++] = 0x0; - } - - /* CRC of the beacon gateway specific part fields */ - field_crc2 = crc16((beacon_pkt.payload + 6 + beacon_RFU1_size), 7 + beacon_RFU2_size); - beacon_pkt.payload[beacon_pyld_idx++] = 0xFF & field_crc2; - beacon_pkt.payload[beacon_pyld_idx++] = 0xFF & (field_crc2 >> 8); - - /* JIT queue initialization */ - jit_queue_init(&jit_queue[0]); - jit_queue_init(&jit_queue[1]); - - while (!exit_sig && !quit_sig) { - - /* auto-quit if the threshold is crossed */ - if ((autoquit_threshold > 0) && (autoquit_cnt >= autoquit_threshold)) { - exit_sig = true; - MSG("INFO: [down] the last %u PULL_DATA were not ACKed, exiting application\n", autoquit_threshold); - break; - } - - /* generate random token for request */ - token_h = (uint8_t)rand(); /* random token */ - token_l = (uint8_t)rand(); /* random token */ - buff_req[1] = token_h; - buff_req[2] = token_l; - - /* send PULL request and record time */ - send(sock_down, (void *)buff_req, sizeof buff_req, 0); - clock_gettime(CLOCK_MONOTONIC, &send_time); - pthread_mutex_lock(&mx_meas_dw); - meas_dw_pull_sent += 1; - pthread_mutex_unlock(&mx_meas_dw); - req_ack = false; - autoquit_cnt++; - - /* listen to packets and process them until a new PULL request must be sent */ - recv_time = send_time; - while ((int)difftimespec(recv_time, send_time) < keepalive_time) { - - /* try to receive a datagram */ - msg_len = recv(sock_down, (void *)buff_down, (sizeof buff_down)-1, 0); - clock_gettime(CLOCK_MONOTONIC, &recv_time); - - /* Pre-allocate beacon slots in JiT queue, to check downlink collisions */ - beacon_loop = JIT_NUM_BEACON_IN_QUEUE - jit_queue[0].num_beacon; - retry = 0; - while (beacon_loop && (beacon_period != 0)) { - pthread_mutex_lock(&mx_timeref); - /* Wait for GPS to be ready before inserting beacons in JiT queue */ - if ((gps_ref_valid == true) && (xtal_correct_ok == true)) { - - /* compute GPS time for next beacon to come */ - /* LoRaWAN: T = k*beacon_period + TBeaconDelay */ - /* with TBeaconDelay = [1.5ms +/- 1µs]*/ - if (last_beacon_gps_time.tv_sec == 0) { - /* if no beacon has been queued, get next slot from current GPS time */ - diff_beacon_time = time_reference_gps.gps.tv_sec % ((time_t)beacon_period); - next_beacon_gps_time.tv_sec = time_reference_gps.gps.tv_sec + - ((time_t)beacon_period - diff_beacon_time); - } else { - /* if there is already a beacon, take it as reference */ - next_beacon_gps_time.tv_sec = last_beacon_gps_time.tv_sec + beacon_period; - } - /* now we can add a beacon_period to the reference to get next beacon GPS time */ - next_beacon_gps_time.tv_sec += (retry * beacon_period); - next_beacon_gps_time.tv_nsec = 0; - -#if DEBUG_BEACON - { - time_t time_unix; - - time_unix = time_reference_gps.gps.tv_sec + UNIX_GPS_EPOCH_OFFSET; - MSG_DEBUG(DEBUG_BEACON, "GPS-now : %s", ctime(&time_unix)); - time_unix = last_beacon_gps_time.tv_sec + UNIX_GPS_EPOCH_OFFSET; - MSG_DEBUG(DEBUG_BEACON, "GPS-last: %s", ctime(&time_unix)); - time_unix = next_beacon_gps_time.tv_sec + UNIX_GPS_EPOCH_OFFSET; - MSG_DEBUG(DEBUG_BEACON, "GPS-next: %s", ctime(&time_unix)); - } -#endif - - /* convert GPS time to concentrator time, and set packet counter for JiT trigger */ - lgw_gps2cnt(time_reference_gps, next_beacon_gps_time, &(beacon_pkt.count_us)); - pthread_mutex_unlock(&mx_timeref); - - /* apply frequency correction to beacon TX frequency */ - if (beacon_freq_nb > 1) { - beacon_chan = (next_beacon_gps_time.tv_sec / beacon_period) % beacon_freq_nb; /* floor rounding */ - } else { - beacon_chan = 0; - } - /* Compute beacon frequency */ - beacon_pkt.freq_hz = beacon_freq_hz + (beacon_chan * beacon_freq_step); - - /* load time in beacon payload */ - beacon_pyld_idx = beacon_RFU1_size; - beacon_pkt.payload[beacon_pyld_idx++] = 0xFF & next_beacon_gps_time.tv_sec; - beacon_pkt.payload[beacon_pyld_idx++] = 0xFF & (next_beacon_gps_time.tv_sec >> 8); - beacon_pkt.payload[beacon_pyld_idx++] = 0xFF & (next_beacon_gps_time.tv_sec >> 16); - beacon_pkt.payload[beacon_pyld_idx++] = 0xFF & (next_beacon_gps_time.tv_sec >> 24); - - /* calculate CRC */ - field_crc1 = crc16(beacon_pkt.payload, 4 + beacon_RFU1_size); /* CRC for the network common part */ - beacon_pkt.payload[beacon_pyld_idx++] = 0xFF & field_crc1; - beacon_pkt.payload[beacon_pyld_idx++] = 0xFF & (field_crc1 >> 8); - - /* Insert beacon packet in JiT queue */ - pthread_mutex_lock(&mx_concent); - lgw_get_instcnt(¤t_concentrator_time); - pthread_mutex_unlock(&mx_concent); - jit_result = jit_enqueue(&jit_queue[0], current_concentrator_time, &beacon_pkt, JIT_PKT_TYPE_BEACON); - if (jit_result == JIT_ERROR_OK) { - /* update stats */ - pthread_mutex_lock(&mx_meas_dw); - meas_nb_beacon_queued += 1; - pthread_mutex_unlock(&mx_meas_dw); - - /* One more beacon in the queue */ - beacon_loop--; - retry = 0; - last_beacon_gps_time.tv_sec = next_beacon_gps_time.tv_sec; /* keep this beacon time as reference for next one to be programmed */ - - /* display beacon payload */ - MSG("INFO: Beacon queued (count_us=%u, freq_hz=%u, size=%u):\n", beacon_pkt.count_us, beacon_pkt.freq_hz, beacon_pkt.size); - printf( " => " ); - for (i = 0; i < beacon_pkt.size; ++i) { - MSG("%02X ", beacon_pkt.payload[i]); - } - MSG("\n"); - } else { - MSG_DEBUG(DEBUG_BEACON, "--> beacon queuing failed with %d\n", jit_result); - /* update stats */ - pthread_mutex_lock(&mx_meas_dw); - if (jit_result != JIT_ERROR_COLLISION_BEACON) { - meas_nb_beacon_rejected += 1; - } - pthread_mutex_unlock(&mx_meas_dw); - /* In case previous enqueue failed, we retry one period later until it succeeds */ - /* Note: In case the GPS has been unlocked for a while, there can be lots of retries */ - /* to be done from last beacon time to a new valid one */ - retry++; - MSG_DEBUG(DEBUG_BEACON, "--> beacon queuing retry=%d\n", retry); - } - } else { - pthread_mutex_unlock(&mx_timeref); - break; - } - } - - /* if no network message was received, got back to listening sock_down socket */ - if (msg_len == -1) { - //MSG("WARNING: [down] recv returned %s\n", strerror(errno)); /* too verbose */ - continue; - } - - /* if the datagram does not respect protocol, just ignore it */ - if ((msg_len < 4) || (buff_down[0] != PROTOCOL_VERSION) || ((buff_down[3] != PKT_PULL_RESP) && (buff_down[3] != PKT_PULL_ACK))) { - MSG("WARNING: [down] ignoring invalid packet len=%d, protocol_version=%d, id=%d\n", - msg_len, buff_down[0], buff_down[3]); - continue; - } - - /* if the datagram is an ACK, check token */ - if (buff_down[3] == PKT_PULL_ACK) { - if ((buff_down[1] == token_h) && (buff_down[2] == token_l)) { - if (req_ack) { - MSG("INFO: [down] duplicate ACK received :)\n"); - } else { /* if that packet was not already acknowledged */ - req_ack = true; - autoquit_cnt = 0; - pthread_mutex_lock(&mx_meas_dw); - meas_dw_ack_rcv += 1; - pthread_mutex_unlock(&mx_meas_dw); - MSG("INFO: [down] PULL_ACK received in %i ms\n", (int)(1000 * difftimespec(recv_time, send_time))); - } - } else { /* out-of-sync token */ - MSG("INFO: [down] received out-of-sync ACK\n"); - } - continue; - } - - /* the datagram is a PULL_RESP */ - buff_down[msg_len] = 0; /* add string terminator, just to be safe */ - MSG("INFO: [down] PULL_RESP received - token[%d:%d] :)\n", buff_down[1], buff_down[2]); /* very verbose */ - printf("\nJSON down: %s\n", (char *)(buff_down + 4)); /* DEBUG: display JSON payload */ - - /* initialize TX struct and try to parse JSON */ - memset(&txpkt, 0, sizeof txpkt); - root_val = json_parse_string_with_comments((const char *)(buff_down + 4)); /* JSON offset */ - if (root_val == NULL) { - MSG("WARNING: [down] invalid JSON, TX aborted\n"); - continue; - } - - /* look for JSON sub-object 'txpk' */ - txpk_obj = json_object_get_object(json_value_get_object(root_val), "txpk"); - if (txpk_obj == NULL) { - MSG("WARNING: [down] no \"txpk\" object in JSON, TX aborted\n"); - json_value_free(root_val); - continue; - } - - /* Parse "immediate" tag, or target timestamp, or UTC time to be converted by GPS (mandatory) */ - i = json_object_get_boolean(txpk_obj,"imme"); /* can be 1 if true, 0 if false, or -1 if not a JSON boolean */ - if (i == 1) { - /* TX procedure: send immediately */ - sent_immediate = true; - downlink_type = JIT_PKT_TYPE_DOWNLINK_CLASS_C; - MSG("INFO: [down] a packet will be sent in \"immediate\" mode\n"); - } else { - sent_immediate = false; - val = json_object_get_value(txpk_obj,"tmst"); - if (val != NULL) { - /* TX procedure: send on timestamp value */ - txpkt.count_us = (uint32_t)json_value_get_number(val); - - /* Concentrator timestamp is given, we consider it is a Class A downlink */ - downlink_type = JIT_PKT_TYPE_DOWNLINK_CLASS_A; - } else { - /* TX procedure: send on GPS time (converted to timestamp value) */ - val = json_object_get_value(txpk_obj, "tmms"); - if (val == NULL) { - MSG("WARNING: [down] no mandatory \"txpk.tmst\" or \"txpk.tmms\" objects in JSON, TX aborted\n"); - json_value_free(root_val); - continue; - } - if (gps_enabled == true) { - pthread_mutex_lock(&mx_timeref); - if (gps_ref_valid == true) { - local_ref = time_reference_gps; - pthread_mutex_unlock(&mx_timeref); - } else { - pthread_mutex_unlock(&mx_timeref); - MSG("WARNING: [down] no valid GPS time reference yet, impossible to send packet on specific GPS time, TX aborted\n"); - json_value_free(root_val); - - /* send acknoledge datagram to server */ - send_tx_ack(buff_down[1], buff_down[2], JIT_ERROR_GPS_UNLOCKED, 0); - continue; - } - } else { - MSG("WARNING: [down] GPS disabled, impossible to send packet on specific GPS time, TX aborted\n"); - json_value_free(root_val); - - /* send acknoledge datagram to server */ - send_tx_ack(buff_down[1], buff_down[2], JIT_ERROR_GPS_UNLOCKED, 0); - continue; - } - - /* Get GPS time from JSON */ - x2 = (uint64_t)json_value_get_number(val); - - /* Convert GPS time from milliseconds to timespec */ - x3 = modf((double)x2/1E3, &x4); - gps_tx.tv_sec = (time_t)x4; /* get seconds from integer part */ - gps_tx.tv_nsec = (long)(x3 * 1E9); /* get nanoseconds from fractional part */ - - /* transform GPS time to timestamp */ - i = lgw_gps2cnt(local_ref, gps_tx, &(txpkt.count_us)); - if (i != LGW_GPS_SUCCESS) { - MSG("WARNING: [down] could not convert GPS time to timestamp, TX aborted\n"); - json_value_free(root_val); - continue; - } else { - MSG("INFO: [down] a packet will be sent on timestamp value %u (calculated from GPS time)\n", txpkt.count_us); - } - - /* GPS timestamp is given, we consider it is a Class B downlink */ - downlink_type = JIT_PKT_TYPE_DOWNLINK_CLASS_B; - } - } - - /* Parse "No CRC" flag (optional field) */ - val = json_object_get_value(txpk_obj,"ncrc"); - if (val != NULL) { - txpkt.no_crc = (bool)json_value_get_boolean(val); - } - - /* parse target frequency (mandatory) */ - val = json_object_get_value(txpk_obj,"freq"); - if (val == NULL) { - MSG("WARNING: [down] no mandatory \"txpk.freq\" object in JSON, TX aborted\n"); - json_value_free(root_val); - continue; - } - txpkt.freq_hz = (uint32_t)((double)(1.0e6) * json_value_get_number(val)); - - /* parse RF chain used for TX (mandatory) */ - val = json_object_get_value(txpk_obj,"rfch"); - if (val == NULL) { - MSG("WARNING: [down] no mandatory \"txpk.rfch\" object in JSON, TX aborted\n"); - json_value_free(root_val); - continue; - } - txpkt.rf_chain = (uint8_t)json_value_get_number(val); - - /* parse TX power (optional field) */ - val = json_object_get_value(txpk_obj,"powe"); - if (val != NULL) { - txpkt.rf_power = (int8_t)json_value_get_number(val) - antenna_gain; - } - - /* Parse modulation (mandatory) */ - str = json_object_get_string(txpk_obj, "modu"); - if (str == NULL) { - MSG("WARNING: [down] no mandatory \"txpk.modu\" object in JSON, TX aborted\n"); - json_value_free(root_val); - continue; - } - if (strcmp(str, "LORA") == 0) { - /* Lora modulation */ - txpkt.modulation = MOD_LORA; - - /* Parse Lora spreading-factor and modulation bandwidth (mandatory) */ - str = json_object_get_string(txpk_obj, "datr"); - if (str == NULL) { - MSG("WARNING: [down] no mandatory \"txpk.datr\" object in JSON, TX aborted\n"); - json_value_free(root_val); - continue; - } - i = sscanf(str, "SF%2hdBW%3hd", &x0, &x1); - if (i != 2) { - MSG("WARNING: [down] format error in \"txpk.datr\", TX aborted\n"); - json_value_free(root_val); - continue; - } - switch (x0) { - case 5: txpkt.datarate = DR_LORA_SF5; break; - case 6: txpkt.datarate = DR_LORA_SF6; break; - case 7: txpkt.datarate = DR_LORA_SF7; break; - case 8: txpkt.datarate = DR_LORA_SF8; break; - case 9: txpkt.datarate = DR_LORA_SF9; break; - case 10: txpkt.datarate = DR_LORA_SF10; break; - case 11: txpkt.datarate = DR_LORA_SF11; break; - case 12: txpkt.datarate = DR_LORA_SF12; break; - default: - MSG("WARNING: [down] format error in \"txpk.datr\", invalid SF, TX aborted\n"); - json_value_free(root_val); - continue; - } - switch (x1) { - case 125: txpkt.bandwidth = BW_125KHZ; break; - case 250: txpkt.bandwidth = BW_250KHZ; break; - case 500: txpkt.bandwidth = BW_500KHZ; break; - default: - MSG("WARNING: [down] format error in \"txpk.datr\", invalid BW, TX aborted\n"); - json_value_free(root_val); - continue; - } - - /* Parse ECC coding rate (optional field) */ - str = json_object_get_string(txpk_obj, "codr"); - if (str == NULL) { - MSG("WARNING: [down] no mandatory \"txpk.codr\" object in json, TX aborted\n"); - json_value_free(root_val); - continue; - } - if (strcmp(str, "4/5") == 0) txpkt.coderate = CR_LORA_4_5; - else if (strcmp(str, "4/6") == 0) txpkt.coderate = CR_LORA_4_6; - else if (strcmp(str, "2/3") == 0) txpkt.coderate = CR_LORA_4_6; - else if (strcmp(str, "4/7") == 0) txpkt.coderate = CR_LORA_4_7; - else if (strcmp(str, "4/8") == 0) txpkt.coderate = CR_LORA_4_8; - else if (strcmp(str, "1/2") == 0) txpkt.coderate = CR_LORA_4_8; - else { - MSG("WARNING: [down] format error in \"txpk.codr\", TX aborted\n"); - json_value_free(root_val); - continue; - } - - /* Parse signal polarity switch (optional field) */ - val = json_object_get_value(txpk_obj,"ipol"); - if (val != NULL) { - txpkt.invert_pol = (bool)json_value_get_boolean(val); - } - - /* parse Lora preamble length (optional field, optimum min value enforced) */ - val = json_object_get_value(txpk_obj,"prea"); - if (val != NULL) { - i = (int)json_value_get_number(val); - if (i >= MIN_LORA_PREAMB) { - txpkt.preamble = (uint16_t)i; - } else { - txpkt.preamble = (uint16_t)MIN_LORA_PREAMB; - } - } else { - txpkt.preamble = (uint16_t)STD_LORA_PREAMB; - } - - } else if (strcmp(str, "FSK") == 0) { - /* FSK modulation */ - txpkt.modulation = MOD_FSK; - - /* parse FSK bitrate (mandatory) */ - val = json_object_get_value(txpk_obj,"datr"); - if (val == NULL) { - MSG("WARNING: [down] no mandatory \"txpk.datr\" object in JSON, TX aborted\n"); - json_value_free(root_val); - continue; - } - txpkt.datarate = (uint32_t)(json_value_get_number(val)); - - /* parse frequency deviation (mandatory) */ - val = json_object_get_value(txpk_obj,"fdev"); - if (val == NULL) { - MSG("WARNING: [down] no mandatory \"txpk.fdev\" object in JSON, TX aborted\n"); - json_value_free(root_val); - continue; - } - txpkt.f_dev = (uint8_t)(json_value_get_number(val) / 1000.0); /* JSON value in Hz, txpkt.f_dev in kHz */ - - /* parse FSK preamble length (optional field, optimum min value enforced) */ - val = json_object_get_value(txpk_obj,"prea"); - if (val != NULL) { - i = (int)json_value_get_number(val); - if (i >= MIN_FSK_PREAMB) { - txpkt.preamble = (uint16_t)i; - } else { - txpkt.preamble = (uint16_t)MIN_FSK_PREAMB; - } - } else { - txpkt.preamble = (uint16_t)STD_FSK_PREAMB; - } - - } else { - MSG("WARNING: [down] invalid modulation in \"txpk.modu\", TX aborted\n"); - json_value_free(root_val); - continue; - } - - /* Parse payload length (mandatory) */ - val = json_object_get_value(txpk_obj,"size"); - if (val == NULL) { - MSG("WARNING: [down] no mandatory \"txpk.size\" object in JSON, TX aborted\n"); - json_value_free(root_val); - continue; - } - txpkt.size = (uint16_t)json_value_get_number(val); - - /* Parse payload data (mandatory) */ - str = json_object_get_string(txpk_obj, "data"); - if (str == NULL) { - MSG("WARNING: [down] no mandatory \"txpk.data\" object in JSON, TX aborted\n"); - json_value_free(root_val); - continue; - } - i = b64_to_bin(str, strlen(str), txpkt.payload, sizeof txpkt.payload); - if (i != txpkt.size) { - MSG("WARNING: [down] mismatch between .size and .data size once converter to binary\n"); - } - - /* free the JSON parse tree from memory */ - json_value_free(root_val); - - /* select TX mode */ - if (sent_immediate) { - txpkt.tx_mode = IMMEDIATE; - } else { - txpkt.tx_mode = TIMESTAMPED; - } - - /* record measurement data */ - pthread_mutex_lock(&mx_meas_dw); - meas_dw_dgram_rcv += 1; /* count only datagrams with no JSON errors */ - meas_dw_network_byte += msg_len; /* meas_dw_network_byte */ - meas_dw_payload_byte += txpkt.size; - pthread_mutex_unlock(&mx_meas_dw); - - /* reset error/warning results */ - jit_result = warning_result = JIT_ERROR_OK; - warning_value = 0; - - /* check TX frequency before trying to queue packet */ - if ((txpkt.freq_hz < tx_freq_min[txpkt.rf_chain]) || (txpkt.freq_hz > tx_freq_max[txpkt.rf_chain])) { - jit_result = JIT_ERROR_TX_FREQ; - MSG("ERROR: Packet REJECTED, unsupported frequency - %u (min:%u,max:%u)\n", txpkt.freq_hz, tx_freq_min[txpkt.rf_chain], tx_freq_max[txpkt.rf_chain]); - } - - /* check TX power before trying to queue packet, send a warning if not supported */ - if (jit_result == JIT_ERROR_OK) { - i = get_tx_gain_lut_index(txpkt.rf_chain, txpkt.rf_power, &tx_lut_idx); - if ((i < 0) || (txlut[txpkt.rf_chain].lut[tx_lut_idx].rf_power != txpkt.rf_power)) { - /* this RF power is not supported, throw a warning, and use the closest lower power supported */ - warning_result = JIT_ERROR_TX_POWER; - warning_value = (int32_t)txlut[txpkt.rf_chain].lut[tx_lut_idx].rf_power; - printf("WARNING: Requested TX power is not supported (%ddBm), actual power used: %ddBm\n", txpkt.rf_power, warning_value); - txpkt.rf_power = txlut[txpkt.rf_chain].lut[tx_lut_idx].rf_power; - } - } - - /* insert packet to be sent into JIT queue */ - if (jit_result == JIT_ERROR_OK) { - pthread_mutex_lock(&mx_concent); - lgw_get_instcnt(¤t_concentrator_time); - pthread_mutex_unlock(&mx_concent); - jit_result = jit_enqueue(&jit_queue[txpkt.rf_chain], current_concentrator_time, &txpkt, downlink_type); - if (jit_result != JIT_ERROR_OK) { - printf("ERROR: Packet REJECTED (jit error=%d)\n", jit_result); - } else { - /* In case of a warning having been raised before, we notify it */ - jit_result = warning_result; - } - pthread_mutex_lock(&mx_meas_dw); - meas_nb_tx_requested += 1; - pthread_mutex_unlock(&mx_meas_dw); - } - - /* Send acknoledge datagram to server */ - send_tx_ack(buff_down[1], buff_down[2], jit_result, warning_value); - } - } - MSG("\nINFO: End of downstream thread\n"); -} - -void print_tx_status(uint8_t tx_status) { - switch (tx_status) { - case TX_OFF: - MSG("INFO: [jit] lgw_status returned TX_OFF\n"); - break; - case TX_FREE: - MSG("INFO: [jit] lgw_status returned TX_FREE\n"); - break; - case TX_EMITTING: - MSG("INFO: [jit] lgw_status returned TX_EMITTING\n"); - break; - case TX_SCHEDULED: - MSG("INFO: [jit] lgw_status returned TX_SCHEDULED\n"); - break; - default: - MSG("INFO: [jit] lgw_status returned UNKNOWN (%d)\n", tx_status); - break; - } -} - - -/* -------------------------------------------------------------------------- */ -/* --- THREAD 3: CHECKING PACKETS TO BE SENT FROM JIT QUEUE AND SEND THEM --- */ - -void thread_jit(void) { - int result = LGW_HAL_SUCCESS; - struct lgw_pkt_tx_s pkt; - int pkt_index = -1; - uint32_t current_concentrator_time; - enum jit_error_e jit_result; - enum jit_pkt_type_e pkt_type; - uint8_t tx_status; - int i; - - while (!exit_sig && !quit_sig) { - wait_ms(10); - - for (i = 0; i < LGW_RF_CHAIN_NB; i++) { - /* transfer data and metadata to the concentrator, and schedule TX */ - pthread_mutex_lock(&mx_concent); - lgw_get_instcnt(¤t_concentrator_time); - pthread_mutex_unlock(&mx_concent); - jit_result = jit_peek(&jit_queue[i], current_concentrator_time, &pkt_index); - if (jit_result == JIT_ERROR_OK) { - if (pkt_index > -1) { - jit_result = jit_dequeue(&jit_queue[i], pkt_index, &pkt, &pkt_type); - if (jit_result == JIT_ERROR_OK) { - /* update beacon stats */ - if (pkt_type == JIT_PKT_TYPE_BEACON) { - /* Compensate breacon frequency with xtal error */ - pthread_mutex_lock(&mx_xcorr); - pkt.freq_hz = (uint32_t)(xtal_correct * (double)pkt.freq_hz); - MSG_DEBUG(DEBUG_BEACON, "beacon_pkt.freq_hz=%u (xtal_correct=%.15lf)\n", pkt.freq_hz, xtal_correct); - pthread_mutex_unlock(&mx_xcorr); - - /* Update statistics */ - pthread_mutex_lock(&mx_meas_dw); - meas_nb_beacon_sent += 1; - pthread_mutex_unlock(&mx_meas_dw); - MSG("INFO: Beacon dequeued (count_us=%u)\n", pkt.count_us); - } - - /* check if concentrator is free for sending new packet */ - pthread_mutex_lock(&mx_concent); /* may have to wait for a fetch to finish */ - result = lgw_status(pkt.rf_chain, TX_STATUS, &tx_status); - pthread_mutex_unlock(&mx_concent); /* free concentrator ASAP */ - if (result == LGW_HAL_ERROR) { - MSG("WARNING: [jit%d] lgw_status failed\n", i); - } else { - if (tx_status == TX_EMITTING) { - MSG("ERROR: concentrator is currently emitting on rf_chain %d\n", i); - print_tx_status(tx_status); - continue; - } else if (tx_status == TX_SCHEDULED) { - MSG("WARNING: a downlink was already scheduled on rf_chain %d, overwritting it...\n", i); - print_tx_status(tx_status); - } else { - /* Nothing to do */ - } - } - - /* send packet to concentrator */ - pthread_mutex_lock(&mx_concent); /* may have to wait for a fetch to finish */ - result = lgw_send(&pkt); - pthread_mutex_unlock(&mx_concent); /* free concentrator ASAP */ - if (result == LGW_HAL_ERROR) { - pthread_mutex_lock(&mx_meas_dw); - meas_nb_tx_fail += 1; - pthread_mutex_unlock(&mx_meas_dw); - MSG("WARNING: [jit] lgw_send failed on rf_chain %d\n", i); - continue; - } else { - pthread_mutex_lock(&mx_meas_dw); - meas_nb_tx_ok += 1; - pthread_mutex_unlock(&mx_meas_dw); - MSG_DEBUG(DEBUG_PKT_FWD, "lgw_send done on rf_chain %d: count_us=%u\n", i, pkt.count_us); - } - } else { - MSG("ERROR: jit_dequeue failed on rf_chain %d with %d\n", i, jit_result); - } - } - } else if (jit_result == JIT_ERROR_EMPTY) { - /* Do nothing, it can happen */ - } else { - MSG("ERROR: jit_peek failed on rf_chain %d with %d\n", i, jit_result); - } - } - } -} - -static void modify_os_time(const uint32_t ppm_tstamp) -{ - struct timespec y; - struct timespec tv; - static bool time_already_set = false; - struct timeval stamp; - gettimeofday(&stamp, NULL); - int time_diff = 0; - lgw_cnt2utc(time_reference_gps, ppm_tstamp, &y); - if ((!gps_enabled) || time_already_set) - { - return; - } - if (y.tv_sec < 1583402711) // time less than '2020-03-05 18:00:00' - { - return; - } - - MSG("INFO: [modify_os_time] local_time=%ld, gps_time=%ld\n", stamp.tv_sec, y.tv_sec); - time_diff = abs(y.tv_sec - stamp.tv_sec); - - if (time_diff < 10) - { - time_already_set = true; - MSG("INFO: [modify_os_time] The difference between the system time(%ld) and the GPS time(%ld) is less than 10 seconds. Use the system time.\n", stamp.tv_sec, y.tv_sec); - return; - } - - tv.tv_sec = y.tv_sec; - tv.tv_nsec = 0; - - int ret = clock_settime(CLOCK_REALTIME, &tv); - if (0 == ret) - { - time_already_set = true; - time_t t; - struct tm* local; - char buf[128] = {0}; - t = time(NULL); - local = localtime(&t); - strftime(buf, 64, "%Y-%m-%d %H:%M:%S", local); - MSG("INFO: [modify_os_time] System time has been synchronized via GPS, %s\n", buf); - } -} - -/* -------------------------------------------------------------------------- */ -/* --- THREAD 4: PARSE GPS MESSAGE AND KEEP GATEWAY IN SYNC ----------------- */ - -static void gps_process_sync(void) { - struct timespec gps_time; - struct timespec utc; - uint32_t trig_tstamp; /* concentrator timestamp associated with PPM pulse */ - int i = lgw_gps_get(&utc, &gps_time, NULL, NULL); - - /* get GPS time for synchronization */ - if (i != LGW_GPS_SUCCESS) { - MSG("WARNING: [gps] could not get GPS time from GPS\n"); - return; - } - - /* get timestamp captured on PPM pulse */ - pthread_mutex_lock(&mx_concent); - i = lgw_get_trigcnt(&trig_tstamp); - pthread_mutex_unlock(&mx_concent); - if (i != LGW_HAL_SUCCESS) { - MSG("WARNING: [gps] failed to read concentrator timestamp\n"); - return; - } - - /* try to update time reference with the new GPS time & timestamp */ - pthread_mutex_lock(&mx_timeref); - i = lgw_gps_sync(&time_reference_gps, trig_tstamp, utc, gps_time); - modify_os_time(trig_tstamp); - pthread_mutex_unlock(&mx_timeref); - if (i != LGW_GPS_SUCCESS) { - MSG("WARNING: [gps] GPS out of sync, keeping previous time reference\n"); - } -} - -static void gps_process_coords(void) { - /* position variable */ - struct coord_s coord; - struct coord_s gpserr; - int i = lgw_gps_get(NULL, NULL, &coord, &gpserr); - - /* update gateway coordinates */ - pthread_mutex_lock(&mx_meas_gps); - if (i == LGW_GPS_SUCCESS) { - gps_coord_valid = true; - meas_gps_coord = coord; - meas_gps_err = gpserr; - // TODO: report other GPS statistics (typ. signal quality & integrity) - } else { - gps_coord_valid = false; - } - pthread_mutex_unlock(&mx_meas_gps); -} - -void thread_gps(void) { - /* serial variables */ - char serial_buff[128]; /* buffer to receive GPS data */ - size_t wr_idx = 0; /* pointer to end of chars in buffer */ - - /* variables for PPM pulse GPS synchronization */ - enum gps_msg latest_msg; /* keep track of latest NMEA message parsed */ - - /* initialize some variables before loop */ - memset(serial_buff, 0, sizeof serial_buff); - - while (!exit_sig && !quit_sig) { - size_t rd_idx = 0; - size_t frame_end_idx = 0; - - /* blocking non-canonical read on serial port */ - ssize_t nb_char = read(gps_tty_fd, serial_buff + wr_idx, LGW_GPS_MIN_MSG_SIZE); - if (nb_char <= 0) { - MSG("WARNING: [gps] read() returned value %zd\n", nb_char); - continue; - } - wr_idx += (size_t)nb_char; - - /******************************************* - * Scan buffer for UBX/NMEA sync chars and * - * attempt to decode frame if one is found * - *******************************************/ - while (rd_idx < wr_idx) { - size_t frame_size = 0; - - /* Scan buffer for UBX sync char */ - if (serial_buff[rd_idx] == (char)LGW_GPS_UBX_SYNC_CHAR) { - - /*********************** - * Found UBX sync char * - ***********************/ - latest_msg = lgw_parse_ubx(&serial_buff[rd_idx], (wr_idx - rd_idx), &frame_size); - - if (frame_size > 0) { - if (latest_msg == INCOMPLETE) { - /* UBX header found but frame appears to be missing bytes */ - frame_size = 0; - } else if (latest_msg == INVALID) { - /* message header received but message appears to be corrupted */ - MSG("WARNING: [gps] could not get a valid message from GPS (no time)\n"); - frame_size = 0; - } else if (latest_msg == UBX_NAV_TIMEGPS) { - gps_process_sync(); - } - } - } else if (serial_buff[rd_idx] == (char)LGW_GPS_NMEA_SYNC_CHAR) { - /************************ - * Found NMEA sync char * - ************************/ - /* scan for NMEA end marker (LF = 0x0a) */ - char* nmea_end_ptr = memchr(&serial_buff[rd_idx],(int)0x0a, (wr_idx - rd_idx)); - - if(nmea_end_ptr) { - /* found end marker */ - frame_size = nmea_end_ptr - &serial_buff[rd_idx] + 1; - latest_msg = lgw_parse_nmea(&serial_buff[rd_idx], frame_size); - - if(latest_msg == INVALID || latest_msg == UNKNOWN) { - /* checksum failed */ - frame_size = 0; - } else if (latest_msg == NMEA_RMC) { /* Get location from RMC frames */ - gps_process_coords(); - } - } - } - - if (frame_size > 0) { - /* At this point message is a checksum verified frame - we're processed or ignored. Remove frame from buffer */ - rd_idx += frame_size; - frame_end_idx = rd_idx; - } else { - rd_idx++; - } - } /* ...for(rd_idx = 0... */ - - if (frame_end_idx) { - /* Frames have been processed. Remove bytes to end of last processed frame */ - memcpy(serial_buff, &serial_buff[frame_end_idx], wr_idx - frame_end_idx); - wr_idx -= frame_end_idx; - } /* ...for(rd_idx = 0... */ - - /* Prevent buffer overflow */ - if ((sizeof(serial_buff) - wr_idx) < LGW_GPS_MIN_MSG_SIZE) { - memcpy(serial_buff, &serial_buff[LGW_GPS_MIN_MSG_SIZE], wr_idx - LGW_GPS_MIN_MSG_SIZE); - wr_idx -= LGW_GPS_MIN_MSG_SIZE; - } - } - MSG("\nINFO: End of GPS thread\n"); -} - -/* -------------------------------------------------------------------------- */ -/* --- THREAD 5: CHECK TIME REFERENCE AND CALCULATE XTAL CORRECTION --------- */ - -void thread_valid(void) { - - /* GPS reference validation variables */ - long gps_ref_age = 0; - bool ref_valid_local = false; - double xtal_err_cpy; - - /* variables for XTAL correction averaging */ - unsigned init_cpt = 0; - double init_acc = 0.0; - double x; - - /* correction debug */ - // FILE * log_file = NULL; - // time_t now_time; - // char log_name[64]; - - /* initialization */ - // time(&now_time); - // strftime(log_name,sizeof log_name,"xtal_err_%Y%m%dT%H%M%SZ.csv",localtime(&now_time)); - // log_file = fopen(log_name, "w"); - // setbuf(log_file, NULL); - // fprintf(log_file,"\"xtal_correct\",\"XERR_INIT_AVG %u XERR_FILT_COEF %u\"\n", XERR_INIT_AVG, XERR_FILT_COEF); // DEBUG - - /* main loop task */ - while (!exit_sig && !quit_sig) { - wait_ms(1000); - - /* calculate when the time reference was last updated */ - pthread_mutex_lock(&mx_timeref); - gps_ref_age = (long)difftime(time(NULL), time_reference_gps.systime); - if ((gps_ref_age >= 0) && (gps_ref_age <= GPS_REF_MAX_AGE)) { - /* time ref is ok, validate and */ - gps_ref_valid = true; - ref_valid_local = true; - xtal_err_cpy = time_reference_gps.xtal_err; - //printf("XTAL err: %.15lf (1/XTAL_err:%.15lf)\n", xtal_err_cpy, 1/xtal_err_cpy); // DEBUG - } else { - /* time ref is too old, invalidate */ - gps_ref_valid = false; - ref_valid_local = false; - } - pthread_mutex_unlock(&mx_timeref); - - /* manage XTAL correction */ - if (ref_valid_local == false) { - /* couldn't sync, or sync too old -> invalidate XTAL correction */ - pthread_mutex_lock(&mx_xcorr); - xtal_correct_ok = false; - xtal_correct = 1.0; - pthread_mutex_unlock(&mx_xcorr); - init_cpt = 0; - init_acc = 0.0; - } else { - if (init_cpt < XERR_INIT_AVG) { - /* initial accumulation */ - init_acc += xtal_err_cpy; - ++init_cpt; - } else if (init_cpt == XERR_INIT_AVG) { - /* initial average calculation */ - pthread_mutex_lock(&mx_xcorr); - xtal_correct = (double)(XERR_INIT_AVG) / init_acc; - //printf("XERR_INIT_AVG=%d, init_acc=%.15lf\n", XERR_INIT_AVG, init_acc); - xtal_correct_ok = true; - pthread_mutex_unlock(&mx_xcorr); - ++init_cpt; - // fprintf(log_file,"%.18lf,\"average\"\n", xtal_correct); // DEBUG - } else { - /* tracking with low-pass filter */ - x = 1 / xtal_err_cpy; - pthread_mutex_lock(&mx_xcorr); - xtal_correct = xtal_correct - xtal_correct/XERR_FILT_COEF + x/XERR_FILT_COEF; - pthread_mutex_unlock(&mx_xcorr); - // 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 - } - MSG("\nINFO: End of validation thread\n"); -} - -/* --- EOF ------------------------------------------------------------------ */ diff --git a/lora/rak2285/loragw_hal.c b/lora/rak2285/loragw_hal.c deleted file mode 100644 index 3f36fe6..0000000 --- a/lora/rak2285/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/rak2285/reset_lgw.sh b/lora/rak2285/reset_lgw.sh deleted file mode 100755 index 2e14c4c..0000000 --- a/lora/rak2285/reset_lgw.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/bin/sh - -# This script is intended to be used on SX1302 CoreCell platform, it performs -# the following actions: -# - export/unpexort GPIO23 and GPIO18 used to reset the SX1302 chip and to enable the LDOs -# -# Usage examples: -# ./reset_lgw.sh stop -# ./reset_lgw.sh start - -# GPIO mapping has to be adapted with HW -# - -SX1302_RESET_PIN=17 -SX1302_POWER_EN_PIN=18 - -WAIT_GPIO() { - sleep 0.1 -} - -init() { - # setup GPIOs - echo "$SX1302_RESET_PIN" > /sys/class/gpio/export; WAIT_GPIO - echo "$SX1302_POWER_EN_PIN" > /sys/class/gpio/export; WAIT_GPIO - - # set GPIOs as output - echo "out" > /sys/class/gpio/gpio$SX1302_RESET_PIN/direction; WAIT_GPIO - echo "out" > /sys/class/gpio/gpio$SX1302_POWER_EN_PIN/direction; WAIT_GPIO -} - -reset() { - echo "CoreCell reset through GPIO$SX1302_RESET_PIN..." - echo "CoreCell power enable through GPIO$SX1302_POWER_EN_PIN..." - - # write output for SX1302 CoreCell power_enable and reset - echo "1" > /sys/class/gpio/gpio$SX1302_POWER_EN_PIN/value; WAIT_GPIO - - echo "1" > /sys/class/gpio/gpio$SX1302_RESET_PIN/value; WAIT_GPIO - echo "0" > /sys/class/gpio/gpio$SX1302_RESET_PIN/value; WAIT_GPIO -} - -term() { - # cleanup all GPIOs - if [ -d /sys/class/gpio/gpio$SX1302_RESET_PIN ] - then - echo "$SX1302_RESET_PIN" > /sys/class/gpio/unexport; WAIT_GPIO - fi - if [ -d /sys/class/gpio/gpio$SX1302_POWER_EN_PIN ] - then - echo "$SX1302_POWER_EN_PIN" > /sys/class/gpio/unexport; WAIT_GPIO - fi -} - -case "$1" in - start) - term # just in case - init - reset - ;; - stop) - reset - term - ;; - *) - echo "Usage: $0 {start|stop}" - exit 1 - ;; -esac - -exit 0 diff --git a/lora/rak2287_spi/global_conf_i2c/global_conf.as_920_923.json b/lora/rak2287/global_conf_i2c/global_conf.as_920_923.json similarity index 100% rename from lora/rak2287_spi/global_conf_i2c/global_conf.as_920_923.json rename to lora/rak2287/global_conf_i2c/global_conf.as_920_923.json diff --git a/lora/rak2287_spi/global_conf_i2c/global_conf.as_923_925.json b/lora/rak2287/global_conf_i2c/global_conf.as_923_925.json similarity index 100% rename from lora/rak2287_spi/global_conf_i2c/global_conf.as_923_925.json rename to lora/rak2287/global_conf_i2c/global_conf.as_923_925.json diff --git a/lora/rak2287_spi/global_conf_i2c/global_conf.au_915_928.json b/lora/rak2287/global_conf_i2c/global_conf.au_915_928.json similarity index 100% rename from lora/rak2287_spi/global_conf_i2c/global_conf.au_915_928.json rename to lora/rak2287/global_conf_i2c/global_conf.au_915_928.json diff --git a/lora/rak2287_spi/global_conf_i2c/global_conf.cn_470_510.json b/lora/rak2287/global_conf_i2c/global_conf.cn_470_510.json similarity index 100% rename from lora/rak2287_spi/global_conf_i2c/global_conf.cn_470_510.json rename to lora/rak2287/global_conf_i2c/global_conf.cn_470_510.json diff --git a/lora/rak2287_spi/global_conf_i2c/global_conf.eu_433.json b/lora/rak2287/global_conf_i2c/global_conf.eu_433.json similarity index 100% rename from lora/rak2287_spi/global_conf_i2c/global_conf.eu_433.json rename to lora/rak2287/global_conf_i2c/global_conf.eu_433.json diff --git a/lora/rak2287_spi/global_conf_i2c/global_conf.eu_863_870.json b/lora/rak2287/global_conf_i2c/global_conf.eu_863_870.json similarity index 100% rename from lora/rak2287_spi/global_conf_i2c/global_conf.eu_863_870.json rename to lora/rak2287/global_conf_i2c/global_conf.eu_863_870.json diff --git a/lora/rak2287_spi/global_conf_i2c/global_conf.in_865_867.json b/lora/rak2287/global_conf_i2c/global_conf.in_865_867.json similarity index 100% rename from lora/rak2287_spi/global_conf_i2c/global_conf.in_865_867.json rename to lora/rak2287/global_conf_i2c/global_conf.in_865_867.json diff --git a/lora/rak2287_spi/global_conf_i2c/global_conf.kr_920_923.json b/lora/rak2287/global_conf_i2c/global_conf.kr_920_923.json similarity index 100% rename from lora/rak2287_spi/global_conf_i2c/global_conf.kr_920_923.json rename to lora/rak2287/global_conf_i2c/global_conf.kr_920_923.json diff --git a/lora/rak2287_spi/global_conf_i2c/global_conf.ru_864_870.json b/lora/rak2287/global_conf_i2c/global_conf.ru_864_870.json similarity index 100% rename from lora/rak2287_spi/global_conf_i2c/global_conf.ru_864_870.json rename to lora/rak2287/global_conf_i2c/global_conf.ru_864_870.json diff --git a/lora/rak2287_spi/global_conf_i2c/global_conf.us_902_928.json b/lora/rak2287/global_conf_i2c/global_conf.us_902_928.json similarity index 100% rename from lora/rak2287_spi/global_conf_i2c/global_conf.us_902_928.json rename to lora/rak2287/global_conf_i2c/global_conf.us_902_928.json diff --git a/lora/rak2287_spi/global_conf_uart/global_conf.as_920_923.json b/lora/rak2287/global_conf_uart/global_conf.as_920_923.json similarity index 100% rename from lora/rak2287_spi/global_conf_uart/global_conf.as_920_923.json rename to lora/rak2287/global_conf_uart/global_conf.as_920_923.json diff --git a/lora/rak2287_spi/global_conf_uart/global_conf.as_923_925.json b/lora/rak2287/global_conf_uart/global_conf.as_923_925.json similarity index 100% rename from lora/rak2287_spi/global_conf_uart/global_conf.as_923_925.json rename to lora/rak2287/global_conf_uart/global_conf.as_923_925.json diff --git a/lora/rak2287_spi/global_conf_uart/global_conf.au_915_928.json b/lora/rak2287/global_conf_uart/global_conf.au_915_928.json similarity index 100% rename from lora/rak2287_spi/global_conf_uart/global_conf.au_915_928.json rename to lora/rak2287/global_conf_uart/global_conf.au_915_928.json diff --git a/lora/rak2287_spi/global_conf_uart/global_conf.cn_470_510.json b/lora/rak2287/global_conf_uart/global_conf.cn_470_510.json similarity index 100% rename from lora/rak2287_spi/global_conf_uart/global_conf.cn_470_510.json rename to lora/rak2287/global_conf_uart/global_conf.cn_470_510.json diff --git a/lora/rak2287_spi/global_conf_uart/global_conf.eu_433.json b/lora/rak2287/global_conf_uart/global_conf.eu_433.json similarity index 100% rename from lora/rak2287_spi/global_conf_uart/global_conf.eu_433.json rename to lora/rak2287/global_conf_uart/global_conf.eu_433.json diff --git a/lora/rak2287_spi/global_conf_uart/global_conf.eu_863_870.json b/lora/rak2287/global_conf_uart/global_conf.eu_863_870.json similarity index 100% rename from lora/rak2287_spi/global_conf_uart/global_conf.eu_863_870.json rename to lora/rak2287/global_conf_uart/global_conf.eu_863_870.json diff --git a/lora/rak2287_spi/global_conf_uart/global_conf.in_865_867.json b/lora/rak2287/global_conf_uart/global_conf.in_865_867.json similarity index 100% rename from lora/rak2287_spi/global_conf_uart/global_conf.in_865_867.json rename to lora/rak2287/global_conf_uart/global_conf.in_865_867.json diff --git a/lora/rak2287_spi/global_conf_uart/global_conf.kr_920_923.json b/lora/rak2287/global_conf_uart/global_conf.kr_920_923.json similarity index 100% rename from lora/rak2287_spi/global_conf_uart/global_conf.kr_920_923.json rename to lora/rak2287/global_conf_uart/global_conf.kr_920_923.json diff --git a/lora/rak2287_spi/global_conf_uart/global_conf.ru_864_870.json b/lora/rak2287/global_conf_uart/global_conf.ru_864_870.json similarity index 100% rename from lora/rak2287_spi/global_conf_uart/global_conf.ru_864_870.json rename to lora/rak2287/global_conf_uart/global_conf.ru_864_870.json diff --git a/lora/rak2287_spi/global_conf_uart/global_conf.us_902_928.json b/lora/rak2287/global_conf_uart/global_conf.us_902_928.json similarity index 100% rename from lora/rak2287_spi/global_conf_uart/global_conf.us_902_928.json rename to lora/rak2287/global_conf_uart/global_conf.us_902_928.json diff --git a/lora/rak2285/global_conf/global_conf.as_920_923.json b/lora/rak2287/global_conf_usb/global_conf.as_920_923.json similarity index 92% rename from lora/rak2285/global_conf/global_conf.as_920_923.json rename to lora/rak2287/global_conf_usb/global_conf.as_920_923.json index 4b90f05..918669e 100755 --- a/lora/rak2285/global_conf/global_conf.as_920_923.json +++ b/lora/rak2287/global_conf_usb/global_conf.as_920_923.json @@ -1,14 +1,14 @@ { "SX130x_conf": { - "spidev_path": "/dev/spidev0.0", + "com_type": "USB", + "com_path": "/dev/ttyACM0", "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/rak2285/global_conf/global_conf.as_923_925.json b/lora/rak2287/global_conf_usb/global_conf.as_923_925.json similarity index 69% rename from lora/rak2285/global_conf/global_conf.as_923_925.json rename to lora/rak2287/global_conf_usb/global_conf.as_923_925.json index 2d8821b..04519e0 100755 --- a/lora/rak2285/global_conf/global_conf.as_923_925.json +++ b/lora/rak2287/global_conf_usb/global_conf.as_923_925.json @@ -1,15 +1,16 @@ { "SX130x_conf": { - "spidev_path": "/dev/spidev0.0", + "com_type": "USB", + "com_path": "/dev/ttyACM0", "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", @@ -20,22 +21,22 @@ "tx_freq_min": 923200000, "tx_freq_max": 925000000, "tx_gain_lut":[ - {"rf_power": 12, "pa_gain": 1, "pwr_idx": 1}, - {"rf_power": 13, "pa_gain": 1, "pwr_idx": 2}, - {"rf_power": 14, "pa_gain": 1, "pwr_idx": 3}, - {"rf_power": 15, "pa_gain": 1, "pwr_idx": 4}, - {"rf_power": 16, "pa_gain": 1, "pwr_idx": 5}, - {"rf_power": 17, "pa_gain": 1, "pwr_idx": 6}, - {"rf_power": 18, "pa_gain": 1, "pwr_idx": 8}, + {"rf_power": 12, "pa_gain": 1, "pwr_idx": 6}, + {"rf_power": 13, "pa_gain": 1, "pwr_idx": 7}, + {"rf_power": 14, "pa_gain": 1, "pwr_idx": 8}, + {"rf_power": 15, "pa_gain": 1, "pwr_idx": 9}, + {"rf_power": 16, "pa_gain": 1, "pwr_idx": 10}, + {"rf_power": 17, "pa_gain": 1, "pwr_idx": 11}, + {"rf_power": 18, "pa_gain": 1, "pwr_idx": 12}, {"rf_power": 19, "pa_gain": 1, "pwr_idx": 13}, - {"rf_power": 20, "pa_gain": 1, "pwr_idx": 10}, + {"rf_power": 20, "pa_gain": 1, "pwr_idx": 14}, {"rf_power": 21, "pa_gain": 1, "pwr_idx": 15}, - {"rf_power": 22, "pa_gain": 1, "pwr_idx": 12}, - {"rf_power": 23, "pa_gain": 1, "pwr_idx": 13}, - {"rf_power": 24, "pa_gain": 1, "pwr_idx": 14}, - {"rf_power": 25, "pa_gain": 1, "pwr_idx": 16}, - {"rf_power": 26, "pa_gain": 1, "pwr_idx": 17}, - {"rf_power": 27, "pa_gain": 1, "pwr_idx": 19} + {"rf_power": 22, "pa_gain": 1, "pwr_idx": 16}, + {"rf_power": 23, "pa_gain": 1, "pwr_idx": 17}, + {"rf_power": 24, "pa_gain": 1, "pwr_idx": 18}, + {"rf_power": 25, "pa_gain": 1, "pwr_idx": 19}, + {"rf_power": 26, "pa_gain": 1, "pwr_idx": 21}, + {"rf_power": 27, "pa_gain": 1, "pwr_idx": 22} ] }, "radio_1": { @@ -46,23 +47,24 @@ "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*/ "chan_multiSF_3": {"enable": true, "radio": 0, "if": 200000}, /* Freq : 923.8 MHz*/ - "chan_multiSF_4": {"enable": true, "radio": 1, "if": 400000}, /* Freq : 924.0 MHz*/ + "chan_multiSF_4": {"enable": true, "radio": 0, "if": 400000}, /* Freq : 924.0 MHz*/ "chan_multiSF_5": {"enable": true, "radio": 1, "if": -400000}, /* Freq : 924.2 MHz*/ "chan_multiSF_6": {"enable": true, "radio": 1, "if": -200000}, /* Freq : 924.4 MHz*/ "chan_multiSF_7": {"enable": true, "radio": 1, "if": 0}, /* Freq : 924.5 MHz*/ "chan_Lora_std": {"enable": true, "radio": 1, "if": -100000, "bandwidth": 250000, "spread_factor": 7, /* Freq : 904.6 MHz*/ "implicit_hdr": false, "implicit_payload_length": 17, "implicit_crc_en": false, "implicit_coderate": 1}, - "chan_FSK": {"enable": true, "radio": 1, "if": 20000, "bandwidth": 125000, "datarate": 50000} /* Freq : 924.8 MHz*/ + "chan_FSK": {"enable": true, "radio": 1, "if": 200000, "bandwidth": 125000, "datarate": 50000} /* Freq : 924.8 MHz*/ }, "gateway_conf": { "gateway_ID": "AA555A0000000000", /* change with default server address/ports */ - "server_address": "router.us.thethings.network", + "server_address": "router.as2.thethings.network", "serv_port_up": 1700, "serv_port_down": 1700, /* adjust the following parameters for your network */ @@ -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/rak2285/global_conf/global_conf.au_915_928.json b/lora/rak2287/global_conf_usb/global_conf.au_915_928.json similarity index 73% rename from lora/rak2285/global_conf/global_conf.au_915_928.json rename to lora/rak2287/global_conf_usb/global_conf.au_915_928.json index 61b16ad..756a21e 100755 --- a/lora/rak2285/global_conf/global_conf.au_915_928.json +++ b/lora/rak2287/global_conf_usb/global_conf.au_915_928.json @@ -1,14 +1,14 @@ { "SX130x_conf": { - "spidev_path": "/dev/spidev0.0", + "com_type": "USB", + "com_path": "/dev/ttyACM0", "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, @@ -20,22 +20,22 @@ "tx_freq_min": 915000000, "tx_freq_max": 928000000, "tx_gain_lut":[ - {"rf_power": 12, "pa_gain": 1, "pwr_idx": 1}, - {"rf_power": 13, "pa_gain": 1, "pwr_idx": 2}, - {"rf_power": 14, "pa_gain": 1, "pwr_idx": 3}, - {"rf_power": 15, "pa_gain": 1, "pwr_idx": 4}, - {"rf_power": 16, "pa_gain": 1, "pwr_idx": 5}, - {"rf_power": 17, "pa_gain": 1, "pwr_idx": 6}, - {"rf_power": 18, "pa_gain": 1, "pwr_idx": 8}, + {"rf_power": 12, "pa_gain": 1, "pwr_idx": 6}, + {"rf_power": 13, "pa_gain": 1, "pwr_idx": 7}, + {"rf_power": 14, "pa_gain": 1, "pwr_idx": 8}, + {"rf_power": 15, "pa_gain": 1, "pwr_idx": 9}, + {"rf_power": 16, "pa_gain": 1, "pwr_idx": 10}, + {"rf_power": 17, "pa_gain": 1, "pwr_idx": 11}, + {"rf_power": 18, "pa_gain": 1, "pwr_idx": 12}, {"rf_power": 19, "pa_gain": 1, "pwr_idx": 13}, - {"rf_power": 20, "pa_gain": 1, "pwr_idx": 10}, + {"rf_power": 20, "pa_gain": 1, "pwr_idx": 14}, {"rf_power": 21, "pa_gain": 1, "pwr_idx": 15}, - {"rf_power": 22, "pa_gain": 1, "pwr_idx": 12}, - {"rf_power": 23, "pa_gain": 1, "pwr_idx": 13}, - {"rf_power": 24, "pa_gain": 1, "pwr_idx": 14}, - {"rf_power": 25, "pa_gain": 1, "pwr_idx": 16}, - {"rf_power": 26, "pa_gain": 1, "pwr_idx": 17}, - {"rf_power": 27, "pa_gain": 1, "pwr_idx": 19} + {"rf_power": 22, "pa_gain": 1, "pwr_idx": 16}, + {"rf_power": 23, "pa_gain": 1, "pwr_idx": 17}, + {"rf_power": 24, "pa_gain": 1, "pwr_idx": 18}, + {"rf_power": 25, "pa_gain": 1, "pwr_idx": 19}, + {"rf_power": 26, "pa_gain": 1, "pwr_idx": 21}, + {"rf_power": 27, "pa_gain": 1, "pwr_idx": 22} ] }, "radio_1": { @@ -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/global_conf_usb/global_conf.cn_470_510.json b/lora/rak2287/global_conf_usb/global_conf.cn_470_510.json new file mode 100755 index 0000000..368e024 --- /dev/null +++ b/lora/rak2287/global_conf_usb/global_conf.cn_470_510.json @@ -0,0 +1,103 @@ +{ + "SX130x_conf": { + "com_type": "USB", + "com_path": "/dev/ttyACM0", + "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/global_conf_usb/global_conf.eu_433.json b/lora/rak2287/global_conf_usb/global_conf.eu_433.json new file mode 100755 index 0000000..a25ad47 --- /dev/null +++ b/lora/rak2287/global_conf_usb/global_conf.eu_433.json @@ -0,0 +1,103 @@ +{ + "SX130x_conf": { + "com_type": "USB", + "com_path": "/dev/ttyACM0", + "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/rak2285/global_conf/global_conf.eu_863_870.json b/lora/rak2287/global_conf_usb/global_conf.eu_863_870.json similarity index 69% rename from lora/rak2285/global_conf/global_conf.eu_863_870.json rename to lora/rak2287/global_conf_usb/global_conf.eu_863_870.json index 8dc6e31..ef5a92e 100755 --- a/lora/rak2285/global_conf/global_conf.eu_863_870.json +++ b/lora/rak2287/global_conf_usb/global_conf.eu_863_870.json @@ -1,14 +1,14 @@ { "SX130x_conf": { - "spidev_path": "/dev/spidev0.0", + "com_type": "USB", + "com_path": "/dev/ttyACM0", "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, @@ -20,22 +20,22 @@ "tx_freq_min": 863000000, "tx_freq_max": 870000000, "tx_gain_lut":[ - {"rf_power": 12, "pa_gain": 1, "pwr_idx": 0}, - {"rf_power": 13, "pa_gain": 1, "pwr_idx": 1}, - {"rf_power": 14, "pa_gain": 1, "pwr_idx": 2}, - {"rf_power": 15, "pa_gain": 1, "pwr_idx": 3}, - {"rf_power": 16, "pa_gain": 1, "pwr_idx": 4}, - {"rf_power": 17, "pa_gain": 1, "pwr_idx": 5}, - {"rf_power": 18, "pa_gain": 1, "pwr_idx": 6}, - {"rf_power": 19, "pa_gain": 1, "pwr_idx": 7}, - {"rf_power": 20, "pa_gain": 1, "pwr_idx": 8}, - {"rf_power": 21, "pa_gain": 1, "pwr_idx": 10}, - {"rf_power": 22, "pa_gain": 1, "pwr_idx": 11}, - {"rf_power": 23, "pa_gain": 1, "pwr_idx": 12}, - {"rf_power": 24, "pa_gain": 1, "pwr_idx": 13}, - {"rf_power": 25, "pa_gain": 1, "pwr_idx": 14}, - {"rf_power": 26, "pa_gain": 1, "pwr_idx": 17}, - {"rf_power": 27, "pa_gain": 1, "pwr_idx": 18} + {"rf_power": 12, "pa_gain": 1, "pwr_idx": 4}, + {"rf_power": 13, "pa_gain": 1, "pwr_idx": 5}, + {"rf_power": 14, "pa_gain": 1, "pwr_idx": 6}, + {"rf_power": 15, "pa_gain": 1, "pwr_idx": 7}, + {"rf_power": 16, "pa_gain": 1, "pwr_idx": 8}, + {"rf_power": 17, "pa_gain": 1, "pwr_idx": 9}, + {"rf_power": 18, "pa_gain": 1, "pwr_idx": 10}, + {"rf_power": 19, "pa_gain": 1, "pwr_idx": 11}, + {"rf_power": 20, "pa_gain": 1, "pwr_idx": 12}, + {"rf_power": 21, "pa_gain": 1, "pwr_idx": 13}, + {"rf_power": 22, "pa_gain": 1, "pwr_idx": 14}, + {"rf_power": 23, "pa_gain": 1, "pwr_idx": 16}, + {"rf_power": 24, "pa_gain": 1, "pwr_idx": 17}, + {"rf_power": 25, "pa_gain": 1, "pwr_idx": 18}, + {"rf_power": 26, "pa_gain": 1, "pwr_idx": 19}, + {"rf_power": 27, "pa_gain": 1, "pwr_idx": 22} ] }, "radio_1": { @@ -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/rak2285/global_conf/global_conf.in_865_867.json b/lora/rak2287/global_conf_usb/global_conf.in_865_867.json similarity index 70% rename from lora/rak2285/global_conf/global_conf.in_865_867.json rename to lora/rak2287/global_conf_usb/global_conf.in_865_867.json index c591b3b..d9b8a90 100755 --- a/lora/rak2285/global_conf/global_conf.in_865_867.json +++ b/lora/rak2287/global_conf_usb/global_conf.in_865_867.json @@ -1,15 +1,16 @@ { "SX130x_conf": { - "spidev_path": "/dev/spidev0.0", + "com_type": "USB", + "com_path": "/dev/ttyACM0", "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", @@ -20,22 +21,22 @@ "tx_freq_min": 865000000, "tx_freq_max": 867000000, "tx_gain_lut":[ - {"rf_power": 12, "pa_gain": 1, "pwr_idx": 0}, - {"rf_power": 13, "pa_gain": 1, "pwr_idx": 1}, - {"rf_power": 14, "pa_gain": 1, "pwr_idx": 2}, - {"rf_power": 15, "pa_gain": 1, "pwr_idx": 3}, - {"rf_power": 16, "pa_gain": 1, "pwr_idx": 4}, - {"rf_power": 17, "pa_gain": 1, "pwr_idx": 5}, - {"rf_power": 18, "pa_gain": 1, "pwr_idx": 6}, - {"rf_power": 19, "pa_gain": 1, "pwr_idx": 7}, - {"rf_power": 20, "pa_gain": 1, "pwr_idx": 8}, - {"rf_power": 21, "pa_gain": 1, "pwr_idx": 10}, - {"rf_power": 22, "pa_gain": 1, "pwr_idx": 11}, - {"rf_power": 23, "pa_gain": 1, "pwr_idx": 12}, - {"rf_power": 24, "pa_gain": 1, "pwr_idx": 13}, - {"rf_power": 25, "pa_gain": 1, "pwr_idx": 14}, - {"rf_power": 26, "pa_gain": 1, "pwr_idx": 17}, - {"rf_power": 27, "pa_gain": 1, "pwr_idx": 18} + {"rf_power": 12, "pa_gain": 1, "pwr_idx": 4}, + {"rf_power": 13, "pa_gain": 1, "pwr_idx": 5}, + {"rf_power": 14, "pa_gain": 1, "pwr_idx": 6}, + {"rf_power": 15, "pa_gain": 1, "pwr_idx": 7}, + {"rf_power": 16, "pa_gain": 1, "pwr_idx": 8}, + {"rf_power": 17, "pa_gain": 1, "pwr_idx": 9}, + {"rf_power": 18, "pa_gain": 1, "pwr_idx": 10}, + {"rf_power": 19, "pa_gain": 1, "pwr_idx": 11}, + {"rf_power": 20, "pa_gain": 1, "pwr_idx": 12}, + {"rf_power": 21, "pa_gain": 1, "pwr_idx": 13}, + {"rf_power": 22, "pa_gain": 1, "pwr_idx": 14}, + {"rf_power": 23, "pa_gain": 1, "pwr_idx": 16}, + {"rf_power": 24, "pa_gain": 1, "pwr_idx": 17}, + {"rf_power": 25, "pa_gain": 1, "pwr_idx": 18}, + {"rf_power": 26, "pa_gain": 1, "pwr_idx": 19}, + {"rf_power": 27, "pa_gain": 1, "pwr_idx": 22} ] }, "radio_1": { @@ -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/rak2285/global_conf/global_conf.kr_920_923.json b/lora/rak2287/global_conf_usb/global_conf.kr_920_923.json similarity index 73% rename from lora/rak2285/global_conf/global_conf.kr_920_923.json rename to lora/rak2287/global_conf_usb/global_conf.kr_920_923.json index 6d54ea7..474dd7c 100755 --- a/lora/rak2285/global_conf/global_conf.kr_920_923.json +++ b/lora/rak2287/global_conf_usb/global_conf.kr_920_923.json @@ -1,14 +1,14 @@ { "SX130x_conf": { - "spidev_path": "/dev/spidev0.0", + "com_type": "USB", + "com_path": "/dev/ttyACM0", "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, @@ -20,22 +20,22 @@ "tx_freq_min": 920900000, "tx_freq_max": 923300000, "tx_gain_lut":[ - {"rf_power": 12, "pa_gain": 1, "pwr_idx": 1}, - {"rf_power": 13, "pa_gain": 1, "pwr_idx": 2}, - {"rf_power": 14, "pa_gain": 1, "pwr_idx": 3}, - {"rf_power": 15, "pa_gain": 1, "pwr_idx": 4}, - {"rf_power": 16, "pa_gain": 1, "pwr_idx": 5}, - {"rf_power": 17, "pa_gain": 1, "pwr_idx": 6}, - {"rf_power": 18, "pa_gain": 1, "pwr_idx": 8}, + {"rf_power": 12, "pa_gain": 1, "pwr_idx": 6}, + {"rf_power": 13, "pa_gain": 1, "pwr_idx": 7}, + {"rf_power": 14, "pa_gain": 1, "pwr_idx": 8}, + {"rf_power": 15, "pa_gain": 1, "pwr_idx": 9}, + {"rf_power": 16, "pa_gain": 1, "pwr_idx": 10}, + {"rf_power": 17, "pa_gain": 1, "pwr_idx": 11}, + {"rf_power": 18, "pa_gain": 1, "pwr_idx": 12}, {"rf_power": 19, "pa_gain": 1, "pwr_idx": 13}, - {"rf_power": 20, "pa_gain": 1, "pwr_idx": 10}, + {"rf_power": 20, "pa_gain": 1, "pwr_idx": 14}, {"rf_power": 21, "pa_gain": 1, "pwr_idx": 15}, - {"rf_power": 22, "pa_gain": 1, "pwr_idx": 12}, - {"rf_power": 23, "pa_gain": 1, "pwr_idx": 13}, - {"rf_power": 24, "pa_gain": 1, "pwr_idx": 14}, - {"rf_power": 25, "pa_gain": 1, "pwr_idx": 16}, - {"rf_power": 26, "pa_gain": 1, "pwr_idx": 17}, - {"rf_power": 27, "pa_gain": 1, "pwr_idx": 19} + {"rf_power": 22, "pa_gain": 1, "pwr_idx": 16}, + {"rf_power": 23, "pa_gain": 1, "pwr_idx": 17}, + {"rf_power": 24, "pa_gain": 1, "pwr_idx": 18}, + {"rf_power": 25, "pa_gain": 1, "pwr_idx": 19}, + {"rf_power": 26, "pa_gain": 1, "pwr_idx": 21}, + {"rf_power": 27, "pa_gain": 1, "pwr_idx": 22} ] }, "radio_1": { @@ -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/rak2285/global_conf/global_conf.ru_864_870.json b/lora/rak2287/global_conf_usb/global_conf.ru_864_870.json similarity index 70% rename from lora/rak2285/global_conf/global_conf.ru_864_870.json rename to lora/rak2287/global_conf_usb/global_conf.ru_864_870.json index acc2c82..4ec3df6 100755 --- a/lora/rak2285/global_conf/global_conf.ru_864_870.json +++ b/lora/rak2287/global_conf_usb/global_conf.ru_864_870.json @@ -1,15 +1,16 @@ { "SX130x_conf": { - "spidev_path": "/dev/spidev0.0", + "com_type": "USB", + "com_path": "/dev/ttyACM0", "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", @@ -20,22 +21,22 @@ "tx_freq_min": 863000000, "tx_freq_max": 870000000, "tx_gain_lut":[ - {"rf_power": 12, "pa_gain": 1, "pwr_idx": 0}, - {"rf_power": 13, "pa_gain": 1, "pwr_idx": 1}, - {"rf_power": 14, "pa_gain": 1, "pwr_idx": 2}, - {"rf_power": 15, "pa_gain": 1, "pwr_idx": 3}, - {"rf_power": 16, "pa_gain": 1, "pwr_idx": 4}, - {"rf_power": 17, "pa_gain": 1, "pwr_idx": 5}, - {"rf_power": 18, "pa_gain": 1, "pwr_idx": 6}, - {"rf_power": 19, "pa_gain": 1, "pwr_idx": 7}, - {"rf_power": 20, "pa_gain": 1, "pwr_idx": 8}, - {"rf_power": 21, "pa_gain": 1, "pwr_idx": 10}, - {"rf_power": 22, "pa_gain": 1, "pwr_idx": 11}, - {"rf_power": 23, "pa_gain": 1, "pwr_idx": 12}, - {"rf_power": 24, "pa_gain": 1, "pwr_idx": 13}, - {"rf_power": 25, "pa_gain": 1, "pwr_idx": 14}, - {"rf_power": 26, "pa_gain": 1, "pwr_idx": 17}, - {"rf_power": 27, "pa_gain": 1, "pwr_idx": 18} + {"rf_power": 12, "pa_gain": 1, "pwr_idx": 4}, + {"rf_power": 13, "pa_gain": 1, "pwr_idx": 5}, + {"rf_power": 14, "pa_gain": 1, "pwr_idx": 6}, + {"rf_power": 15, "pa_gain": 1, "pwr_idx": 7}, + {"rf_power": 16, "pa_gain": 1, "pwr_idx": 8}, + {"rf_power": 17, "pa_gain": 1, "pwr_idx": 9}, + {"rf_power": 18, "pa_gain": 1, "pwr_idx": 10}, + {"rf_power": 19, "pa_gain": 1, "pwr_idx": 11}, + {"rf_power": 20, "pa_gain": 1, "pwr_idx": 12}, + {"rf_power": 21, "pa_gain": 1, "pwr_idx": 13}, + {"rf_power": 22, "pa_gain": 1, "pwr_idx": 14}, + {"rf_power": 23, "pa_gain": 1, "pwr_idx": 16}, + {"rf_power": 24, "pa_gain": 1, "pwr_idx": 17}, + {"rf_power": 25, "pa_gain": 1, "pwr_idx": 18}, + {"rf_power": 26, "pa_gain": 1, "pwr_idx": 19}, + {"rf_power": 27, "pa_gain": 1, "pwr_idx": 22} ] }, "radio_1": { @@ -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/rak2285/global_conf/global_conf.us_902_928.json b/lora/rak2287/global_conf_usb/global_conf.us_902_928.json similarity index 73% rename from lora/rak2285/global_conf/global_conf.us_902_928.json rename to lora/rak2287/global_conf_usb/global_conf.us_902_928.json index 9a5d472..4d6120f 100755 --- a/lora/rak2285/global_conf/global_conf.us_902_928.json +++ b/lora/rak2287/global_conf_usb/global_conf.us_902_928.json @@ -1,15 +1,16 @@ { "SX130x_conf": { - "spidev_path": "/dev/spidev0.0", + "com_type": "USB", + "com_path": "/dev/ttyACM0", "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", @@ -20,22 +21,22 @@ "tx_freq_min": 923000000, "tx_freq_max": 928000000, "tx_gain_lut":[ - {"rf_power": 12, "pa_gain": 1, "pwr_idx": 1}, - {"rf_power": 13, "pa_gain": 1, "pwr_idx": 2}, - {"rf_power": 14, "pa_gain": 1, "pwr_idx": 3}, - {"rf_power": 15, "pa_gain": 1, "pwr_idx": 4}, - {"rf_power": 16, "pa_gain": 1, "pwr_idx": 5}, - {"rf_power": 17, "pa_gain": 1, "pwr_idx": 6}, - {"rf_power": 18, "pa_gain": 1, "pwr_idx": 8}, + {"rf_power": 12, "pa_gain": 1, "pwr_idx": 6}, + {"rf_power": 13, "pa_gain": 1, "pwr_idx": 7}, + {"rf_power": 14, "pa_gain": 1, "pwr_idx": 8}, + {"rf_power": 15, "pa_gain": 1, "pwr_idx": 9}, + {"rf_power": 16, "pa_gain": 1, "pwr_idx": 10}, + {"rf_power": 17, "pa_gain": 1, "pwr_idx": 11}, + {"rf_power": 18, "pa_gain": 1, "pwr_idx": 12}, {"rf_power": 19, "pa_gain": 1, "pwr_idx": 13}, - {"rf_power": 20, "pa_gain": 1, "pwr_idx": 10}, + {"rf_power": 20, "pa_gain": 1, "pwr_idx": 14}, {"rf_power": 21, "pa_gain": 1, "pwr_idx": 15}, - {"rf_power": 22, "pa_gain": 1, "pwr_idx": 12}, - {"rf_power": 23, "pa_gain": 1, "pwr_idx": 13}, - {"rf_power": 24, "pa_gain": 1, "pwr_idx": 14}, - {"rf_power": 25, "pa_gain": 1, "pwr_idx": 16}, - {"rf_power": 26, "pa_gain": 1, "pwr_idx": 17}, - {"rf_power": 27, "pa_gain": 1, "pwr_idx": 19} + {"rf_power": 22, "pa_gain": 1, "pwr_idx": 16}, + {"rf_power": 23, "pa_gain": 1, "pwr_idx": 17}, + {"rf_power": 24, "pa_gain": 1, "pwr_idx": 18}, + {"rf_power": 25, "pa_gain": 1, "pwr_idx": 19}, + {"rf_power": 26, "pa_gain": 1, "pwr_idx": 21}, + {"rf_power": 27, "pa_gain": 1, "pwr_idx": 22} ] }, "radio_1": { @@ -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/install.sh similarity index 100% rename from lora/rak2287_spi/install.sh rename to lora/rak2287/install.sh diff --git a/lora/rak2287_spi/lora_pkt_fwd.c b/lora/rak2287/lora_pkt_fwd.c similarity index 100% rename from lora/rak2287_spi/lora_pkt_fwd.c rename to lora/rak2287/lora_pkt_fwd.c diff --git a/lora/rak2287_spi/loragw_gps.c b/lora/rak2287/loragw_gps.c similarity index 100% rename from lora/rak2287_spi/loragw_gps.c rename to lora/rak2287/loragw_gps.c diff --git a/lora/rak2287_spi/loragw_stts751.c b/lora/rak2287/loragw_stts751.c similarity index 100% rename from lora/rak2287_spi/loragw_stts751.c rename to lora/rak2287/loragw_stts751.c diff --git a/lora/rak2287_spi/reset_lgw.sh b/lora/rak2287/reset_lgw.sh similarity index 100% rename from lora/rak2287_spi/reset_lgw.sh rename to lora/rak2287/reset_lgw.sh diff --git a/lora/rak2287_spi/test_loragw_gps_i2c.c b/lora/rak2287/test_loragw_gps_i2c.c similarity index 100% rename from lora/rak2287_spi/test_loragw_gps_i2c.c rename to lora/rak2287/test_loragw_gps_i2c.c diff --git a/lora/rak2287_spi/test_loragw_gps_uart.c b/lora/rak2287/test_loragw_gps_uart.c similarity index 100% rename from lora/rak2287_spi/test_loragw_gps_uart.c rename to lora/rak2287/test_loragw_gps_uart.c diff --git a/rak/gateway-version b/rak/gateway-version index 790807f..6051080 100755 --- a/rak/gateway-version +++ b/rak/gateway-version @@ -17,12 +17,22 @@ if [ "${RAK_MODEL}" = "RAK2247" ] || [ "${RAK_MODEL}" = "RAK833" ]; then else GW_MODEL_STR="${RAK_MODEL} for USB" fi -elif [ "${RAK_MODEL}" = "RAK7243" ] || [ "${RAK_MODEL}" = "RAK7244" ] || [ "${RAK_MODEL}" = "RAK7248" ]; then +elif [ "${RAK_MODEL}" = "RAK7243" ] || [ "${RAK_MODEL}" = "RAK7244" ]; then if [ "$INSTALL_LTE" = "1" ]; then GW_MODEL_STR="${RAK_MODEL} with LTE" else GW_MODEL_STR="${RAK_MODEL} no LTE" fi +elif [ "${RAK_MODEL}" = "RAK7248" ] || [ "${RAK_MODEL}" = "RAK2287" ]; then + if [ "${LORA_SPI}" = "1" ]; then + if [ "$INSTALL_LTE" = "1" ]; then + GW_MODEL_STR="${RAK_MODEL} with LTE" + else + GW_MODEL_STR="${RAK_MODEL} no LTE" + fi + else + GW_MODEL_STR="${RAK_MODEL} for USB" + fi else GW_MODEL_STR=$RAK_MODEL fi diff --git a/rak/rak/bin/active_lte_module.sh b/rak/rak/bin/active_lte_module.sh index 9df169e..a4e7fbf 100755 --- a/rak/rak/bin/active_lte_module.sh +++ b/rak/rak/bin/active_lte_module.sh @@ -3,21 +3,21 @@ cd /sys/class/gpio/ echo 5 > export echo 6 > export -echo 13 > export -echo 19 > export +#echo 13 > export +#echo 19 > export echo 21 > export echo 26 > export echo out > gpio5/direction echo out > gpio6/direction -echo out > gpio13/direction -echo out > gpio19/direction +#echo out > gpio13/direction +#echo out > gpio19/direction echo in > gpio21/direction echo out > gpio26/direction echo 0 > gpio5/value echo 0 > gpio6/value -echo 0 > gpio13/value -echo 0 > gpio19/value +#echo 0 > gpio13/value +#echo 0 > gpio19/value echo 0 > gpio26/value diff --git a/rak/rak/first_boot/copy_pkt_fwd b/rak/rak/first_boot/copy_pkt_fwd index 6fb9415..598005f 100755 --- a/rak/rak/first_boot/copy_pkt_fwd +++ b/rak/rak/first_boot/copy_pkt_fwd @@ -20,16 +20,8 @@ if [ ! -d "/opt/ttn-gateway/packet_forwarder" ]; then fi elif [ "$GW_MODEL" = "RAK7248" ]; then - if [ "$LORA_SPI" = "1" ]; then - cp /usr/local/rak/lora/rak2287_spi/* /opt/ttn-gateway/ -rf - if [ "$INSTALL_LTE" = "1" ]; then - cp /usr/local/rak/lora/rak2287_spi/global_conf_i2c /opt/ttn-gateway/packet_forwarder/lora_pkt_fwd/global_conf -rf - else - cp /usr/local/rak/lora/rak2287_spi/global_conf_uart /opt/ttn-gateway/packet_forwarder/lora_pkt_fwd/global_conf -rf - fi - else - cp /usr/local/rak/lora/rak2287_usb/* /opt/ttn-gateway/ -rf - fi + cp /usr/local/rak/lora/rak2287/* /opt/ttn-gateway/ -rf + cp /usr/local/rak/lora/rak2287/global_conf_i2c /opt/ttn-gateway/packet_forwarder/lora_pkt_fwd/global_conf -rf else echo "some error." fi @@ -43,8 +35,15 @@ if [ ! -d "/opt/ttn-gateway/packet_forwarder" ]; then elif [ "$GW_MODEL" = "RAK2246" ]; then cp /usr/local/rak/lora/rak2246/* /opt/ttn-gateway/ -rf elif [ "$GW_MODEL" = "RAK7248" ]; then - cp /usr/local/rak/lora/rak2287_spi/* /opt/ttn-gateway/ -rf - cp /usr/local/rak/lora/rak2287_spi/global_conf_uart /opt/ttn-gateway/packet_forwarder/lora_pkt_fwd/global_conf -rf + cp /usr/local/rak/lora/rak2287/* /opt/ttn-gateway/ -rf + cp /usr/local/rak/lora/rak2287/global_conf_uart /opt/ttn-gateway/packet_forwarder/lora_pkt_fwd/global_conf -rf + elif [ "$GW_MODEL" = "RAK2287" ]; then + cp /usr/local/rak/lora/rak2287/* /opt/ttn-gateway/ -rf + if [ "$LORA_SPI" = "1" ]; then + cp /usr/local/rak/lora/rak2287/global_conf_uart /opt/ttn-gateway/packet_forwarder/lora_pkt_fwd/global_conf -rf + else + cp /usr/local/rak/lora/rak2287/global_conf_usb /opt/ttn-gateway/packet_forwarder/lora_pkt_fwd/global_conf -rf + fi else cp /usr/local/rak/lora/rak7243/* /opt/ttn-gateway/ -rf cp /usr/local/rak/lora/rak7243/global_conf_uart /opt/ttn-gateway/packet_forwarder/lora_pkt_fwd/global_conf -rf