From f991b0e35ad1bd3b999c70e68c518bae91bd36a6 Mon Sep 17 00:00:00 2001 From: Sylvain Miermont Date: Fri, 28 Mar 2014 16:58:48 +0100 Subject: v1.3.0 - Added TX power management. - Added full support for SX1301 reference board. - Changed build system with configuration for multiple chip/radio/band support. - SX125x bandwidth set to 1MHz by default (was 800 kHz). - Solved warnings with 64b integer printf when compiling on x86_64. - Renamed helper programs to reduce the concentrator vs. gateway confusion. --- libloragw/src/loragw_hal.c | 569 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 435 insertions(+), 134 deletions(-) (limited to 'libloragw/src/loragw_hal.c') diff --git a/libloragw/src/loragw_hal.c b/libloragw/src/loragw_hal.c index 3ab1cb5..e21c5a1 100644 --- a/libloragw/src/loragw_hal.c +++ b/libloragw/src/loragw_hal.c @@ -4,10 +4,10 @@ \____ \| ___ | (_ _) ___ |/ ___) _ \ _____) ) ____| | | || |_| ____( (___| | | | (______/|_____)_|_|_| \__)_____)\____)_| |_| - ©2013 Semtech-Cycleo + (C)2013 Semtech-Cycleo Description: - Lora gateway Hardware Abstraction Layer + LoRa concentrator Hardware Abstraction Layer License: Revised BSD License, see LICENSE.TXT file include in the project Maintainer: Sylvain Miermont @@ -47,28 +47,36 @@ Maintainer: Sylvain Miermont #define TRACE() fprintf(stderr, "@ %s %d\n", __FUNCTION__, __LINE__); /* -------------------------------------------------------------------------- */ -/* --- PRIVATE CONSTANTS ---------------------------------------------------- */ +/* --- PRIVATE CONSTANTS & TYPES -------------------------------------------- */ #define MCU_ARB 0 #define MCU_AGC 1 -const uint8_t ifmod_config[LGW_IF_CHAIN_NB] = LGW_IFMODEM_CONFIG; /* define hardware capability */ - -const uint32_t rf_rx_lowfreq[LGW_RF_CHAIN_NB] = LGW_RF_RX_LOWFREQ; -const uint32_t rf_rx_upfreq[LGW_RF_CHAIN_NB] = LGW_RF_RX_UPFREQ; -const uint32_t rf_rx_bandwidth[LGW_RF_CHAIN_NB] = LGW_RF_RX_BANDWIDTH; -const uint32_t rf_tx_lowfreq[LGW_RF_CHAIN_NB] = LGW_RF_TX_LOWFREQ; -const uint32_t rf_tx_upfreq[LGW_RF_CHAIN_NB] = LGW_RF_TX_UPFREQ; - #define MCU_ARB_FW_BYTE 8192 /* size of the firmware IN BYTES (= twice the number of 14b words) */ #define MCU_AGC_FW_BYTE 8192 /* size of the firmware IN BYTES (= twice the number of 14b words) */ +#define TX_METADATA_NB 16 +#define RX_METADATA_NB 16 + +#define MIN_LORA_PREAMBLE 4 +#define STD_LORA_PREAMBLE 6 +#define MIN_FSK_PREAMBLE 3 +#define PLL_LOCK_MAX_ATTEMPTS 5 + +#define TX_START_DELAY 1500 + /* SX1257 frequency setting : F_register(24bit) = F_rf (Hz) / F_step(Hz) = F_rf (Hz) * 2^19 / F_xtal(Hz) = F_rf (Hz) * 2^19 / 32e6 = F_rf (Hz) * 256/15625 + +SX1255 frequency setting : +F_register(24bit) = F_rf (Hz) / F_step(Hz) + = F_rf (Hz) * 2^20 / F_xtal(Hz) + = F_rf (Hz) * 2^20 / 32e6 + = F_rf (Hz) * 512/15625 */ #define SX125x_32MHz_FRAC 15625 /* irreductible fraction for PLL register caculation */ @@ -80,23 +88,203 @@ F_register(24bit) = F_rf (Hz) / F_step(Hz) #define SX125x_TX_DAC_BW 7 /* 24 + 8*TxDacBw Nb FIR taps (default 2) */ #define SX125x_RX_LNA_GAIN 1 /* 1 to 6, 1 highest gain */ #define SX125x_RX_BB_GAIN 12 /* 0 to 15 , 15 highest gain */ -#define SX125x_RX_ADC_BW 7 /* 0 to 7, 2:100 radio A, 1 -> radio B */ -static int32_t if_freq[LGW_IF_CHAIN_NB] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; /* relative to radio frequency, +/- in Hz */ +static bool if_enable[LGW_IF_CHAIN_NB]; +static bool if_rf_chain[LGW_IF_CHAIN_NB]; /* for each IF, 0 -> radio A, 1 -> radio B */ +static int32_t if_freq[LGW_IF_CHAIN_NB]; /* relative to radio frequency, +/- in Hz */ -static uint8_t lora_multi_sfmask[LGW_MULTI_NB] = {0, 0, 0, 0}; /* enables SF for Lora 'multi' modems */ +static uint8_t lora_multi_sfmask[LGW_MULTI_NB]; /* enables SF for LoRa 'multi' modems */ -static uint8_t lora_rx_bw = 0; /* bandwidth setting for Lora standalone modem */ -static uint8_t lora_rx_sf = 0; /* spreading factor setting for Lora standalone modem */ -static bool lora_rx_ppm_offset = 0; +static uint8_t lora_rx_bw; /* bandwidth setting for LoRa standalone modem */ +static uint8_t lora_rx_sf; /* spreading factor setting for LoRa standalone modem */ +static bool lora_rx_ppm_offset; -static uint8_t fsk_rx_bw = 0; /* bandwidth setting of FSK modem */ -static uint32_t fsk_rx_dr = 0; /* FSK modem datarate in bauds */ +static uint8_t fsk_rx_bw; /* bandwidth setting of FSK modem */ +static uint32_t fsk_rx_dr; /* FSK modem datarate in bauds */ /* -------------------------------------------------------------------------- */ /* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */ @@ -144,7 +328,7 @@ void sx125x_write(uint8_t channel, uint8_t addr, uint8_t data); uint8_t sx125x_read(uint8_t channel, uint8_t addr); -int setup_sx1257(uint8_t rf_chain, uint32_t freq_hz); +int setup_sx125x(uint8_t rf_chain, uint32_t freq_hz); void lgw_constant_adjust(void); @@ -287,7 +471,7 @@ uint8_t sx125x_read(uint8_t channel, uint8_t addr) { /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -int setup_sx1257(uint8_t rf_chain, uint32_t freq_hz) { +int setup_sx125x(uint8_t rf_chain, uint32_t freq_hz) { uint32_t part_int; uint32_t part_frac; int cpt_attempts = 0; @@ -297,37 +481,61 @@ int setup_sx1257(uint8_t rf_chain, uint32_t freq_hz) { return -1; } - sx125x_write(rf_chain, 0x10, SX125x_TX_DAC_CLK_SEL + 2); /* Enable 'clock out' for both radios */ - sx125x_write(rf_chain, 0x26, 0X2D); /* Disable gm of oscillator block */ - - /* Tx gain and trim */ - sx125x_write(rf_chain, 0x08, SX125x_TX_MIX_GAIN + SX125x_TX_DAC_GAIN*16); - sx125x_write(rf_chain, 0x0A, SX125x_TX_ANA_BW + SX125x_TX_PLL_BW*32); - sx125x_write(rf_chain, 0x0B, SX125x_TX_DAC_BW); - - /* Rx gain and trim */ - sx125x_write(rf_chain, 0x0C, 0 + SX125x_RX_BB_GAIN*2 + SX125x_RX_LNA_GAIN*32); - sx125x_write(rf_chain, 0x0D, SX125x_RXBB_BW + SX125x_RX_ADC_TRIM*4 + SX125x_RX_ADC_BW*32); - - /* set RX PLL frequency */ - part_int = freq_hz / (SX125x_32MHz_FRAC << 8); /* integer part, gives the MSB */ - part_frac = ((freq_hz % (SX125x_32MHz_FRAC << 8)) << 8) / SX125x_32MHz_FRAC; /* fractional part, gives middle part and LSB */ - sx125x_write(rf_chain, 0x01,0xFF & part_int); /* Most Significant Byte */ - sx125x_write(rf_chain, 0x02,0xFF & (part_frac >> 8)); /* middle byte */ - sx125x_write(rf_chain, 0x03,0xFF & part_frac); /* Least Significant Byte */ - - /* start and PLL lock */ - do { - if (cpt_attempts >= PLL_LOCK_MAX_ATTEMPTS) { - DEBUG_MSG("ERROR: FAIL TO LOCK PLL\n"); - return -1; - } - sx125x_write(rf_chain, 0x00, 1); /* enable Xtal oscillator */ - sx125x_write(rf_chain, 0x00, 3); /* Enable RX (PLL+FE) */ - ++cpt_attempts; - DEBUG_PRINTF("Note: SX125x #%d PLL start (attempt %d)\n", rf_chain, cpt_attempts); - wait_ms(1); - } while((sx125x_read(rf_chain, 0x11) & 0x02) == 0); + /* Get version to identify SX1255/57 silicon revision */ + DEBUG_PRINTF("Note: SX125x #%d version register returned 0x%02x\n", rf_chain, sx125x_read(rf_chain, 0x07)); + + /* General radio setup */ + if (rf_clkout[rf_chain] == true) { + sx125x_write(rf_chain, 0x10, SX125x_TX_DAC_CLK_SEL + 2); + DEBUG_PRINTF("Note: SX125x #%d clock output enabled\n", rf_chain); + } else { + sx125x_write(rf_chain, 0x10, SX125x_TX_DAC_CLK_SEL); + DEBUG_PRINTF("Note: SX125x #%d clock output disabled\n", rf_chain); + } + #if (CFG_RADIO_1257 == 1) + sx125x_write(rf_chain, 0x26, SX125x_XOSC_GM_STARTUP + SX125x_XOSC_DISABLE*16); + #elif (CFG_RADIO_1255 == 1) + sx125x_write(rf_chain, 0x28, SX125x_XOSC_GM_STARTUP + SX125x_XOSC_DISABLE*16); + #endif + + if (rf_enable[rf_chain] == true) { + /* Tx gain and trim */ + sx125x_write(rf_chain, 0x08, SX125x_TX_MIX_GAIN + SX125x_TX_DAC_GAIN*16); + sx125x_write(rf_chain, 0x0A, SX125x_TX_ANA_BW + SX125x_TX_PLL_BW*32); + sx125x_write(rf_chain, 0x0B, SX125x_TX_DAC_BW); + + /* Rx gain and trim */ + sx125x_write(rf_chain, 0x0C, SX125x_LNA_ZIN + SX125x_RX_BB_GAIN*2 + SX125x_RX_LNA_GAIN*32); + sx125x_write(rf_chain, 0x0D, SX125x_RX_BB_BW + SX125x_RX_ADC_TRIM*4 + SX125x_RX_ADC_BW*32); + sx125x_write(rf_chain, 0x0E, SX125x_ADC_TEMP + SX125x_RX_PLL_BW*2); + + /* set RX PLL frequency */ + #if (CFG_RADIO_1257 == 1) + part_int = freq_hz / (SX125x_32MHz_FRAC << 8); /* integer part, gives the MSB */ + part_frac = ((freq_hz % (SX125x_32MHz_FRAC << 8)) << 8) / SX125x_32MHz_FRAC; /* fractional part, gives middle part and LSB */ + #elif (CFG_RADIO_1255 == 1) + part_int = freq_hz / (SX125x_32MHz_FRAC << 7); /* integer part, gives the MSB */ + part_frac = ((freq_hz % (SX125x_32MHz_FRAC << 7)) << 9) / SX125x_32MHz_FRAC; /* fractional part, gives middle part and LSB */ + #endif + sx125x_write(rf_chain, 0x01,0xFF & part_int); /* Most Significant Byte */ + sx125x_write(rf_chain, 0x02,0xFF & (part_frac >> 8)); /* middle byte */ + sx125x_write(rf_chain, 0x03,0xFF & part_frac); /* Least Significant Byte */ + + /* start and PLL lock */ + do { + if (cpt_attempts >= PLL_LOCK_MAX_ATTEMPTS) { + DEBUG_MSG("ERROR: FAIL TO LOCK PLL\n"); + return -1; + } + sx125x_write(rf_chain, 0x00, 1); /* enable Xtal oscillator */ + sx125x_write(rf_chain, 0x00, 3); /* Enable RX (PLL+FE) */ + ++cpt_attempts; + DEBUG_PRINTF("Note: SX125x #%d PLL start (attempt %d)\n", rf_chain, cpt_attempts); + wait_ms(1); + } while((sx125x_read(rf_chain, 0x11) & 0x02) == 0); + } else { + DEBUG_PRINTF("Note: SX125x #%d kept in standby mode\n", rf_chain); + } return 0; } @@ -343,14 +551,14 @@ void lgw_constant_adjust(void) { // lgw_reg_w(LGW_RX_EDGE_SELECT,0); /* default 0 */ // lgw_reg_w(LGW_MBWSSF_MODEM_INVERT_IQ,0); /* default 0 */ // lgw_reg_w(LGW_DC_NOTCH_EN,1); /* default 1 */ - lgw_reg_w(LGW_RSSI_BB_FILTER_ALPHA,9); /* default 7 */ - lgw_reg_w(LGW_RSSI_DEC_FILTER_ALPHA,9); /* default 5 */ + lgw_reg_w(LGW_RSSI_BB_FILTER_ALPHA,6); /* default 7 */ + lgw_reg_w(LGW_RSSI_DEC_FILTER_ALPHA,7); /* default 5 */ lgw_reg_w(LGW_RSSI_CHANN_FILTER_ALPHA,7); /* default 8 */ - // lgw_reg_w(LGW_RSSI_BB_DEFAULT_VALUE,32); /* default 32 */ - lgw_reg_w(LGW_RSSI_CHANN_DEFAULT_VALUE,90); /* default 100 */ - lgw_reg_w(LGW_RSSI_DEC_DEFAULT_VALUE,90); /* default 100 */ - // lgw_reg_w(LGW_DEC_GAIN_OFFSET, 8); /* default 8 */ - // lgw_reg_w(LGW_CHAN_GAIN_OFFSET, 7); /* default 7 */ + lgw_reg_w(LGW_RSSI_BB_DEFAULT_VALUE,23); /* default 32 */ + lgw_reg_w(LGW_RSSI_CHANN_DEFAULT_VALUE,85); /* default 100 */ + lgw_reg_w(LGW_RSSI_DEC_DEFAULT_VALUE,66); /* default 100 */ + lgw_reg_w(LGW_DEC_GAIN_OFFSET,7); /* default 8 */ + lgw_reg_w(LGW_CHAN_GAIN_OFFSET,6); /* default 7 */ /* Correlator setup */ // lgw_reg_w(LGW_CORR_DETECT_EN,126); /* default 126 */ @@ -371,9 +579,8 @@ void lgw_constant_adjust(void) { // lgw_reg_w(LGW_CORR_SIG_NOISE_RATIO_SF11,4); /* default 4 */ // lgw_reg_w(LGW_CORR_SIG_NOISE_RATIO_SF12,4); /* default 4 */ - /* Lora 'multi' demodulators setup */ - lgw_reg_w(LGW_PREAMBLE_SYMB1_NB,4); /* default 10 */ - // lgw_reg_w(LGW_FREQ_TO_TIME_DRIFT,9); /* default 9 */ + /* LoRa 'multi' demodulators setup */ + // lgw_reg_w(LGW_PREAMBLE_SYMB1_NB,10); /* default 10 */ // lgw_reg_w(LGW_FREQ_TO_TIME_INVERT,29); /* default 29 */ // lgw_reg_w(LGW_FRAME_SYNCH_GAIN,1); /* default 1 */ // lgw_reg_w(LGW_SYNCH_DETECT_TH,1); /* default 1 */ @@ -389,10 +596,8 @@ void lgw_constant_adjust(void) { // lgw_reg_w(LGW_ADJUST_MODEM_START_OFFSET_SF12_RDX4,4092); /* default 4092 */ // lgw_reg_w(LGW_MAX_PAYLOAD_LEN,255); /* default 255 */ - /* Lora standalone 'MBWSSF' demodulator setup */ - // lgw_reg_w(LGW_MBWSSF_MODEM_ENABLE,1); /* default 0 */ + /* LoRa standalone 'MBWSSF' demodulator setup */ // lgw_reg_w(LGW_MBWSSF_PREAMBLE_SYMB1_NB,10); /* default 10 */ - // lgw_reg_w(LGW_MBWSSF_FREQ_TO_TIME_DRIFT,36); /* default 36 */ // lgw_reg_w(LGW_MBWSSF_FREQ_TO_TIME_INVERT,29); /* default 29 */ // lgw_reg_w(LGW_MBWSSF_FRAME_SYNCH_GAIN,1); /* default 1 */ // lgw_reg_w(LGW_MBWSSF_SYNCH_DETECT_TH,1); /* default 1 */ @@ -429,7 +634,7 @@ void lgw_constant_adjust(void) { /* TX general parameters */ lgw_reg_w(LGW_TX_START_DELAY, TX_START_DELAY); /* default 0 */ - /* TX Lora */ + /* TX LoRa */ // lgw_reg_w(LGW_TX_MODE,0); /* default 0 */ lgw_reg_w(LGW_TX_SWAP_IQ,1); /* "normal" polarity; default 0 */ @@ -448,9 +653,9 @@ void lgw_constant_adjust(void) { int lgw_rxrf_setconf(uint8_t rf_chain, struct lgw_conf_rxrf_s conf) { - /* check if the gateway is running */ + /* check if the concentrator is running */ if (lgw_is_started == true) { - DEBUG_MSG("ERROR: GATEWAY IS RUNNING, STOP IT BEFORE TOUCHING CONFIGURATION\n"); + DEBUG_MSG("ERROR: CONCENTRATOR IS RUNNING, STOP IT BEFORE TOUCHING CONFIGURATION\n"); return LGW_HAL_ERROR; } @@ -473,15 +678,17 @@ int lgw_rxrf_setconf(uint8_t rf_chain, struct lgw_conf_rxrf_s conf) { rf_enable[rf_chain] = conf.enable; rf_rx_freq[rf_chain] = conf.freq_hz; + DEBUG_PRINTF("Note: rf_chain %d configuration; en:%d freq:%d\n", rf_chain, rf_enable[rf_chain], rf_rx_freq[rf_chain]); + return LGW_HAL_SUCCESS; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ int lgw_rxif_setconf(uint8_t if_chain, struct lgw_conf_rxif_s conf) { - /* check if the gateway is running */ + /* check if the concentrator is running */ if (lgw_is_started == true) { - DEBUG_MSG("ERROR: GATEWAY IS RUNNING, STOP IT BEFORE TOUCHING CONFIGURATION\n"); + DEBUG_MSG("ERROR: CONCENTRATOR IS RUNNING, STOP IT BEFORE TOUCHING CONFIGURATION\n"); return LGW_HAL_ERROR; } @@ -543,12 +750,12 @@ int lgw_rxif_setconf(uint8_t if_chain, struct lgw_conf_rxif_s conf) { lora_rx_bw = conf.bandwidth; lora_rx_sf = (uint8_t)(DR_LORA_MULTI & conf.datarate); /* filter SF out of the 7-12 range */ if (SET_PPM_ON(conf.bandwidth, conf.datarate)) { - lora_rx_ppm_offset = 1; + lora_rx_ppm_offset = true; } else { - lora_rx_ppm_offset = 0; + lora_rx_ppm_offset = false; } - DEBUG_PRINTF("Note: Lora 'std' if_chain %d configured; en:%d freq:%d bw:%d dr:%d\n", if_chain, if_enable[if_chain], if_freq[if_chain], lora_rx_bw, lora_rx_sf); + DEBUG_PRINTF("Note: LoRa 'std' if_chain %d configuration; en:%d freq:%d bw:%d dr:%d\n", if_chain, if_enable[if_chain], if_freq[if_chain], lora_rx_bw, lora_rx_sf); break; case IF_LORA_MULTI: @@ -574,7 +781,7 @@ int lgw_rxif_setconf(uint8_t if_chain, struct lgw_conf_rxif_s conf) { if_freq[if_chain] = conf.freq_hz; lora_multi_sfmask[if_chain] = (uint8_t)(DR_LORA_MULTI & conf.datarate); /* filter SF out of the 7-12 range */ - DEBUG_PRINTF("Note: Lora 'multi' if_chain %d configured; en:%d freq:%d SF_mask:0x%02x\n", if_chain, if_enable[if_chain], if_freq[if_chain], lora_multi_sfmask[if_chain]); + DEBUG_PRINTF("Note: LoRa 'multi' if_chain %d configuration; en:%d freq:%d SF_mask:0x%02x\n", if_chain, if_enable[if_chain], if_freq[if_chain], lora_multi_sfmask[if_chain]); break; case IF_FSK_STD: @@ -600,7 +807,7 @@ int lgw_rxif_setconf(uint8_t if_chain, struct lgw_conf_rxif_s conf) { if_freq[if_chain] = conf.freq_hz; fsk_rx_bw = conf.bandwidth; fsk_rx_dr = conf.datarate; - DEBUG_PRINTF("Note: FSK if_chain %d configured; en:%d freq:%d bw:%d dr:%d (%d real dr)\n", if_chain, if_enable[if_chain], if_freq[if_chain], fsk_rx_bw, fsk_rx_dr, LGW_XTAL_FREQU/(LGW_XTAL_FREQU/fsk_rx_dr)); + DEBUG_PRINTF("Note: FSK if_chain %d configuration; en:%d freq:%d bw:%d dr:%d (%d real dr)\n", if_chain, if_enable[if_chain], if_freq[if_chain], fsk_rx_bw, fsk_rx_dr, LGW_XTAL_FREQU/(LGW_XTAL_FREQU/fsk_rx_dr)); break; default: @@ -614,11 +821,15 @@ int lgw_rxif_setconf(uint8_t if_chain, struct lgw_conf_rxif_s conf) { /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ int lgw_start(void) { - int i, j; + int i; int reg_stat; + unsigned x; + uint8_t radio_select; + int32_t read_val; + uint8_t load_val; if (lgw_is_started == true) { - DEBUG_MSG("Note: Lora Gateway already started, restarting it now\n"); + DEBUG_MSG("Note: LoRa concentrator already started, restarting it now\n"); } reg_stat = lgw_connect(); @@ -634,25 +845,16 @@ int lgw_start(void) { lgw_reg_w(LGW_GLOBAL_EN, 1); /* switch on and reset the radios (also starts the 32 MHz XTAL) */ - lgw_reg_w(LGW_RADIO_A_EN,1); /* radio A *must* be started to get 32 MHz clk */ - lgw_reg_w(LGW_RADIO_B_EN,1); /* radio B *must* be started because they share the same XTAL I/O is clamped to ground when off */ + lgw_reg_w(LGW_RADIO_A_EN,1); + lgw_reg_w(LGW_RADIO_B_EN,1); wait_ms(500); lgw_reg_w(LGW_RADIO_RST,1); wait_ms(5); lgw_reg_w(LGW_RADIO_RST,0); /* setup the radios */ - if (rf_enable[0] == 1) { - setup_sx1257(0, rf_rx_freq[0]); - } - if (rf_enable[1] == 1) { - setup_sx1257(1, rf_rx_freq[1]); - } - - /* gives the AGC MCU control over radio, RF front-end and filter gain */ - lgw_reg_w(LGW_FORCE_HOST_RADIO_CTRL,0); - lgw_reg_w(LGW_FORCE_HOST_FE_CTRL,0); - lgw_reg_w(LGW_FORCE_DEC_FILTER_GAIN,0); + setup_sx125x(0, rf_rx_freq[0]); + setup_sx125x(1, rf_rx_freq[1]); /* TODO load the calibration firmware and wait for calibration to end */ @@ -667,28 +869,58 @@ int lgw_start(void) { /* load adjusted parameters */ lgw_constant_adjust(); - /* configure Lora 'multi' demodulators aka. Lora 'sensor' channels (IF0-3) */ - j = 0; - for(i=0; i<=7; ++i) { - j += (if_rf_chain[i] == 1 ? 1 << i : 0); /* transform bool array into binary word */ + /* Freq-to-time-drift calculation */ + x = (2 * 8192000000) / (uint64_t)(rf_rx_lowfreq[0] + rf_rx_upfreq[0]); /* 64b calculation */ + if (x > 63) { + x = 63; } - lgw_reg_w(LGW_RADIO_SELECT, j); /* IF mapping to radio A/B (per bit, 0=A, 1=B) */ + lgw_reg_w(LGW_FREQ_TO_TIME_DRIFT, x); /* default 9 */ + x = (2 * 32768000000) / (uint64_t)(rf_rx_lowfreq[0] + rf_rx_upfreq[0]); /* 64b calculation */ + if (x > 63) { + x = 63; + } + lgw_reg_w(LGW_MBWSSF_FREQ_TO_TIME_DRIFT, x); /* default 36 */ + + /* configure LoRa 'multi' demodulators aka. LoRa 'sensor' channels (IF0-3) */ + + radio_select = 0; /* IF mapping to radio A/B (per bit, 0=A, 1=B) */ + for(i=0; iif_chain, ifmod); if ((ifmod == IF_LORA_MULTI) || (ifmod == IF_LORA_STD)) { - DEBUG_MSG("Note: Lora packet\n"); + DEBUG_MSG("Note: LoRa packet\n"); switch(stat_fifo & 0x07) { case 5: p->status = STAT_CRC_OK; @@ -872,7 +1160,7 @@ int lgw_receive(uint8_t max_pkt, struct lgw_pkt_rx_s *pkt_data) { } /* timestamp correction code, base delay */ - if (ifmod == IF_LORA_STD) { /* if packet was received on the stand-alone lora modem */ + if (ifmod == IF_LORA_STD) { /* if packet was received on the stand-alone LoRa modem */ switch (lora_rx_bw) { case BW_125KHZ: delay_x = 64; @@ -966,11 +1254,11 @@ int lgw_send(struct lgw_pkt_tx_s pkt_data) { uint16_t fsk_dr_div; /* divider to configure for target datarate */ int transfer_size = 0; /* data to transfer from host to TX databuffer */ int payload_offset = 0; /* start of the payload content in the databuffer */ - uint8_t power_nibble = 0; /* 4-bit value to set the firmware TX power */ + uint8_t pow_index = 0; /* 4-bit value to set the firmware TX power */ - /* check if the gateway is running */ + /* check if the concentrator is running */ if (lgw_is_started == false) { - DEBUG_MSG("ERROR: GATEWAY IS NOT RUNNING, START IT BEFORE SENDING\n"); + DEBUG_MSG("ERROR: CONCENTRATOR IS NOT RUNNING, START IT BEFORE SENDING\n"); return LGW_HAL_ERROR; } @@ -981,6 +1269,10 @@ int lgw_send(struct lgw_pkt_tx_s pkt_data) { } /* check input variables */ + if (rf_tx_enable[pkt_data.rf_chain] == false) { + DEBUG_MSG("ERROR: SELECTED RF_CHAIN IS DISABLED FOR TX ON SELECTED BOARD\n"); + return LGW_HAL_ERROR; + } if (rf_enable[pkt_data.rf_chain] == false) { DEBUG_MSG("ERROR: SELECTED RF_CHAIN IS DISABLED\n"); return LGW_HAL_ERROR; @@ -1032,20 +1324,25 @@ int lgw_send(struct lgw_pkt_tx_s pkt_data) { } /* interpretation of TX power */ - if (pkt_data.rf_power < 24) { - power_nibble = 0x0; /* ~15.5 dBm, so 14 after cavity filter + cables */ - } else { - power_nibble = 0xF; /* maximum power ~25.5 dBm, 24 after filter */ + for (pow_index = TX_POW_LUT_SIZE-1; pow_index > 0; pow_index--) { + if (tx_pow_table[pow_index].rf_power <= pkt_data.rf_power) { + break; + } } - // TODO: implement LUT in the firmware and matched value in the HAL /* fixed metadata, useful payload and misc metadata compositing */ transfer_size = TX_METADATA_NB + pkt_data.size; /* */ payload_offset = TX_METADATA_NB; /* start the payload just after the metadata */ /* metadata 0 to 2, TX PLL frequency */ + #if (CFG_RADIO_1257 == 1) part_int = pkt_data.freq_hz / (SX125x_32MHz_FRAC << 8); /* integer part, gives the MSB */ part_frac = ((pkt_data.freq_hz % (SX125x_32MHz_FRAC << 8)) << 8) / SX125x_32MHz_FRAC; /* fractional part, gives middle part and LSB */ + #elif (CFG_RADIO_1255 == 1) + part_int = pkt_data.freq_hz / (SX125x_32MHz_FRAC << 7); /* integer part, gives the MSB */ + part_frac = ((pkt_data.freq_hz % (SX125x_32MHz_FRAC << 7)) << 9) / SX125x_32MHz_FRAC; /* fractional part, gives middle part and LSB */ + #endif + buff[0] = 0xFF & part_int; /* Most Significant Byte */ buff[1] = 0xFF & (part_frac >> 8); /* middle byte */ buff[2] = 0xFF & part_frac; /* Least Significant Byte */ @@ -1059,11 +1356,11 @@ int lgw_send(struct lgw_pkt_tx_s pkt_data) { /* parameters depending on modulation */ if (pkt_data.modulation == MOD_LORA) { /* metadata 7, modulation type, radio chain selection and TX power */ - buff[7] = (0x20 & (pkt_data.rf_chain << 5)) | (0x0F & power_nibble); /* bit 4 is 0 -> Lora modulation */ + buff[7] = (0x20 & (pkt_data.rf_chain << 5)) | (0x0F & pow_index); /* bit 4 is 0 -> LoRa modulation */ buff[8] = 0; /* metadata 8, not used */ - /* metadata 9, CRC, Lora CR & SF */ + /* metadata 9, CRC, LoRa CR & SF */ switch (pkt_data.datarate) { case DR_LORA_SF7: buff[9] = 7; break; case DR_LORA_SF8: buff[9] = 8; break; @@ -1082,6 +1379,8 @@ int lgw_send(struct lgw_pkt_tx_s pkt_data) { } if (pkt_data.no_crc == false) { buff[9] |= 0x80; /* set 'CRC enable' bit */ + } else { + DEBUG_MSG("Info: packet will be sent without CRC\n"); } /* metadata 10, payload size */ @@ -1104,10 +1403,12 @@ int lgw_send(struct lgw_pkt_tx_s pkt_data) { buff[11] |= 0x10; /* set 'TX polarity' bit at 1 */ } - /* metadata 12 & 13, Lora preamble size */ - if (pkt_data.preamble < MIN_LORA_PREAMBLE) { /* enforce minimum preamble size */ + /* metadata 12 & 13, LoRa preamble size */ + if (pkt_data.preamble == 0) { /* if not explicit, use recommended LoRa preamble size */ + pkt_data.preamble = STD_LORA_PREAMBLE; + } else if (pkt_data.preamble < MIN_LORA_PREAMBLE) { /* enforce minimum preamble size */ pkt_data.preamble = MIN_LORA_PREAMBLE; - DEBUG_MSG("Note: preamble length adjusted to respect minimum Lora preamble size\n"); + DEBUG_MSG("Note: preamble length adjusted to respect minimum LoRa preamble size\n"); } buff[12] = 0xFF & (pkt_data.preamble >> 8); buff[13] = 0xFF & pkt_data.preamble; @@ -1118,7 +1419,7 @@ int lgw_send(struct lgw_pkt_tx_s pkt_data) { } else if (pkt_data.modulation == MOD_FSK) { /* metadata 7, modulation type, radio chain selection and TX power */ - buff[7] = (0x20 & (pkt_data.rf_chain << 5)) | 0x10 | (0x0F & power_nibble); /* bit 4 is 1 -> FSK modulation */ + buff[7] = (0x20 & (pkt_data.rf_chain << 5)) | 0x10 | (0x0F & pow_index); /* bit 4 is 1 -> FSK modulation */ buff[8] = 0; /* metadata 8, not used */ -- cgit v1.2.3