From a955619271b5d0a46d32e08150acfbc1eed183b7 Mon Sep 17 00:00:00 2001 From: Michael Coracin Date: Wed, 5 Apr 2017 13:34:03 +0200 Subject: [PATCH] v5.0.1 * HAL: Reworked the way the TX start delay is calculated, taking into account the delay introduced by TX notch filter (when enabled) and the delay linked to signal bandwidth separately. --- VERSION | 2 +- libloragw/inc/loragw_fpga.h | 11 +++++ libloragw/inc/loragw_lbt.h | 2 +- libloragw/inc/loragw_reg.h | 12 ------ libloragw/src/loragw_fpga.c | 42 ++++++++++++++----- libloragw/src/loragw_hal.c | 84 +++++++++++++++++++++++-------------- libloragw/src/loragw_lbt.c | 6 +-- libloragw/src/loragw_reg.c | 17 -------- readme.md | 6 +++ 9 files changed, 106 insertions(+), 76 deletions(-) diff --git a/VERSION b/VERSION index 0062ac97..6b244dcd 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -5.0.0 +5.0.1 diff --git a/libloragw/inc/loragw_fpga.h b/libloragw/inc/loragw_fpga.h index 82a763df..f599f730 100644 --- a/libloragw/inc/loragw_fpga.h +++ b/libloragw/inc/loragw_fpga.h @@ -84,6 +84,17 @@ this file is autogenerated from registers description /* -------------------------------------------------------------------------- */ /* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */ +/** +@brief LoRa concentrator TX notch filter delay +@return delay in microseconds introduced by TX notch filter +*/ +float lgw_fpga_get_tx_notch_delay(void); + +/** +@brief LoRa concentrator FPGA configuration +@param tx_notch_freq TX notch filter frequency, in Hertz +@return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR) +*/ int lgw_fpga_configure(uint32_t tx_notch_freq); /** diff --git a/libloragw/inc/loragw_lbt.h b/libloragw/inc/loragw_lbt.h index a8ca1574..cb8aada2 100644 --- a/libloragw/inc/loragw_lbt.h +++ b/libloragw/inc/loragw_lbt.h @@ -58,7 +58,7 @@ int lbt_start(void); @param tx_allowed pointer to receive permission for transmission @return LGW_LBT_ERROR id the operation failed, LGW_LBT_SUCCESS else */ -int lbt_is_channel_free(struct lgw_pkt_tx_s * pkt_data, bool * tx_allowed); +int lbt_is_channel_free(struct lgw_pkt_tx_s * pkt_data, uint16_t tx_start_delay, bool * tx_allowed); /** @brief Check if LBT is enabled diff --git a/libloragw/inc/loragw_reg.h b/libloragw/inc/loragw_reg.h index 7353889e..2a944a76 100644 --- a/libloragw/inc/loragw_reg.h +++ b/libloragw/inc/loragw_reg.h @@ -41,12 +41,6 @@ struct lgw_reg_s { int32_t dflt; /*!< register default value */ }; -enum lgw_brd_version_e { - LGW_BRD_VERSION_1_0, /*!< Gateway v1.0 (no FPGA) */ - LGW_BRD_VERSION_1_5, /*!< Gateway v1.5 (with FPGA) */ - LGW_BRD_VERSION_UNKNOWN /*!< Unknown */ -}; - /* -------------------------------------------------------------------------- */ /* --- INTERNAL SHARED FUNCTIONS -------------------------------------------- */ @@ -414,12 +408,6 @@ int lgw_connect(bool spi_only, uint32_t tx_notch_freq); */ int lgw_disconnect(void); -/** -@brief Get LoRa concentrator board version -@return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR) -*/ -int lgw_brd_version(enum lgw_brd_version_e * brd_version); - /** @brief Use the soft-reset register to put the concentrator in initial state @return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR) diff --git a/libloragw/src/loragw_fpga.c b/libloragw/src/loragw_fpga.c index 6c94dbf0..465f43eb 100644 --- a/libloragw/src/loragw_fpga.c +++ b/libloragw/src/loragw_fpga.c @@ -99,6 +99,11 @@ const struct lgw_reg_s fpga_regs[LGW_FPGA_TOTALREGS] = { extern void *lgw_spi_target; /*! generic pointer to the SPI device */ extern uint8_t lgw_spi_mux_mode; /*! current SPI mux mode used */ +/* -------------------------------------------------------------------------- */ +/* --- PRIVATE VARIABLES ---------------------------------------------------- */ +static bool tx_notch_support = false; +static uint8_t tx_notch_offset; + /* -------------------------------------------------------------------------- */ /* --- PRIVATE FUNCTIONS ---------------------------------------------------- */ @@ -108,10 +113,25 @@ extern uint8_t lgw_spi_mux_mode; /*! current SPI mux mode used */ /* -------------------------------------------------------------------------- */ /* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */ +float lgw_fpga_get_tx_notch_delay(void) { + float tx_notch_delay; + + if (tx_notch_support == false) { + return 0; + } + + /* Notch filtering performed by FPGA adds a constant delay (group delay) that we need to compensate */ + tx_notch_delay = (31.25 * ((64 + tx_notch_offset) / 2)) / 1E3; /* 32MHz => 31.25ns */ + + return tx_notch_delay; +} + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + int lgw_fpga_configure(uint32_t tx_notch_freq) { int x; - int32_t val, notch_offset_reg; - bool tx_filter_support, spectral_scan_support, lbt_support; + int32_t val; + bool spectral_scan_support, lbt_support; /* Check input parameters */ if ((tx_notch_freq < LGW_MIN_NOTCH_FREQ) || (tx_notch_freq > LGW_MAX_NOTCH_FREQ)) { @@ -122,16 +142,16 @@ int lgw_fpga_configure(uint32_t tx_notch_freq) { /* Get supported FPGA features */ printf("INFO: FPGA supported features:"); lgw_fpga_reg_r(LGW_FPGA_FEATURE, &val); - tx_filter_support = TAKE_N_BITS_FROM((uint8_t)val, 0, 1); - if (tx_filter_support) { + tx_notch_support = TAKE_N_BITS_FROM((uint8_t)val, 0, 1); + if (tx_notch_support == true) { printf(" [TX filter] "); } spectral_scan_support = TAKE_N_BITS_FROM((uint8_t)val, 1, 1); - if (spectral_scan_support) { + if (spectral_scan_support == true) { printf(" [Spectral Scan] "); } lbt_support = TAKE_N_BITS_FROM((uint8_t)val, 2, 1); - if (lbt_support) { + if (lbt_support == true) { printf(" [LBT] "); } printf("\n"); @@ -152,9 +172,9 @@ int lgw_fpga_configure(uint32_t tx_notch_freq) { } /* Configure TX notch filter */ - if (tx_filter_support == true) { - notch_offset_reg = (32E6 / (2*tx_notch_freq)) - 64; - x = lgw_fpga_reg_w(LGW_FPGA_NOTCH_FREQ_OFFSET, notch_offset_reg); + if (tx_notch_support == true) { + tx_notch_offset = (32E6 / (2*tx_notch_freq)) - 64; + x = lgw_fpga_reg_w(LGW_FPGA_NOTCH_FREQ_OFFSET, (int32_t)tx_notch_offset); if (x != LGW_REG_SUCCESS) { DEBUG_MSG("ERROR: Failed to configure FPGA TX notch filter\n"); return LGW_REG_ERROR; @@ -166,10 +186,10 @@ int lgw_fpga_configure(uint32_t tx_notch_freq) { DEBUG_MSG("ERROR: Failed to read FPGA TX notch frequency\n"); return LGW_REG_ERROR; } - if (val != notch_offset_reg) { + if (val != tx_notch_offset) { DEBUG_MSG("WARNING: TX notch filter frequency is not programmable (check your FPGA image)\n"); } else { - DEBUG_PRINTF("INFO: TX notch filter frequency set to %u (%i)\n", tx_notch_freq, notch_offset_reg); + DEBUG_PRINTF("INFO: TX notch filter frequency set to %u (%i)\n", tx_notch_freq, tx_notch_offset); } } diff --git a/libloragw/src/loragw_hal.c b/libloragw/src/loragw_hal.c index c8055028..81037518 100644 --- a/libloragw/src/loragw_hal.c +++ b/libloragw/src/loragw_hal.c @@ -85,6 +85,8 @@ Maintainer: Sylvain Miermont #define LGW_RF_RX_BANDWIDTH_250KHZ 1000000 /* for 250KHz channels */ #define LGW_RF_RX_BANDWIDTH_500KHZ 1100000 /* for 500KHz channels */ +#define TX_START_DELAY_DEFAULT 1497 /* Calibrated value for 500KHz BW and notch filter disabled */ + /* constant arrays defining hardware capability */ const uint8_t ifmod_config[LGW_IF_CHAIN_NB] = LGW_IFMODEM_CONFIG; @@ -157,12 +159,6 @@ static int8_t cal_offset_a_q[8]; /* TX Q offset for radio A */ static int8_t cal_offset_b_i[8]; /* TX I offset for radio B */ static int8_t cal_offset_b_q[8]; /* TX Q offset for radio B */ -/* -------------------------------------------------------------------------- */ -/* --- INTERNAL SHARED VARIABLES -------------------------------------------- */ - -/* TX start delay adjusted for the concentrator board used */ -uint16_t lgw_i_tx_start_delay_us = 1500; /* shared with LBT module */ - /* -------------------------------------------------------------------------- */ /* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */ @@ -332,7 +328,7 @@ void lgw_constant_adjust(void) { lgw_reg_w(LGW_FSK_PATTERN_TIMEOUT_CFG,128); /* sync timeout (allow 8 bytes preamble + 8 bytes sync word, default 0 */ /* TX general parameters */ - lgw_reg_w(LGW_TX_START_DELAY, (int32_t)lgw_i_tx_start_delay_us); /* default 0 */ + lgw_reg_w(LGW_TX_START_DELAY, TX_START_DELAY_DEFAULT); /* default 0 */ /* TX LoRa */ // lgw_reg_w(LGW_TX_MODE,0); /* default 0 */ @@ -383,6 +379,36 @@ int32_t lgw_sf_getval(int x) { } } +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +uint16_t lgw_get_tx_start_delay(bool tx_notch_enable, uint8_t bw) { + float notch_delay_us = 0.0; + float bw_delay_us = 0.0; + float tx_start_delay; + + /* Notch filtering performed by FPGA adds a constant delay (group delay) that we need to compensate */ + if (tx_notch_enable) { + notch_delay_us = lgw_fpga_get_tx_notch_delay(); + } + + /* Calibrated delay brought by SX1301 depending on signal bandwidth */ + switch (bw) { + case BW_125KHZ: + bw_delay_us = 1.5; + break; + case BW_500KHZ: + /* Intended fall-through: it is the calibrated reference */ + default: + break; + } + + tx_start_delay = (float)TX_START_DELAY_DEFAULT - bw_delay_us - notch_delay_us; + + printf("INFO: tx_start_delay=%u (%f) - (%u, bw_delay=%f, notch_delay=%f)\n", (uint16_t)tx_start_delay, tx_start_delay, TX_START_DELAY_DEFAULT, bw_delay_us, notch_delay_us); + + return (uint16_t)tx_start_delay; /* keep truncating instead of rounding: better behaviour measured */ +} + /* -------------------------------------------------------------------------- */ /* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */ @@ -678,7 +704,6 @@ int lgw_start(void) { uint8_t cal_cmd; uint16_t cal_time; uint8_t cal_status; - enum lgw_brd_version_e brd_version = LGW_BRD_VERSION_UNKNOWN; uint64_t fsk_sync_word_reg; @@ -692,24 +717,6 @@ int lgw_start(void) { return LGW_HAL_ERROR; } - /* Adjust parameters which depends on the concentrator board version */ - reg_stat = lgw_brd_version(&brd_version); - if ((reg_stat == LGW_REG_ERROR) || (brd_version == LGW_BRD_VERSION_UNKNOWN)) { - DEBUG_MSG("ERROR: FAIL TO GET BOARD VERSION\n"); - return LGW_HAL_ERROR; - } - switch (brd_version) { - case LGW_BRD_VERSION_1_0: - lgw_i_tx_start_delay_us = 1495; /* adjusted to send Class-B beacons at 1500µs after PPS +/-1µs */ - break; - case LGW_BRD_VERSION_1_5: - lgw_i_tx_start_delay_us = 1494; /* adjusted to send Class-B beacons at 1500µs after PPS +/-1µs */ - break; - default: - /* nothing to do */ - break; - } - /* reset the registers (also shuts the radios down) */ lgw_soft_reset(); @@ -1335,6 +1342,8 @@ int lgw_send(struct lgw_pkt_tx_s pkt_data) { uint8_t target_mix_gain = 0; /* used to select the proper I/Q offset correction */ uint32_t count_trig = 0; /* timestamp value in trigger mode corrected for TX start delay */ bool tx_allowed = false; + uint16_t tx_start_delay; + bool tx_notch_enable = false; /* check if the concentrator is running */ if (lgw_is_started == false) { @@ -1396,6 +1405,14 @@ int lgw_send(struct lgw_pkt_tx_s pkt_data) { return LGW_HAL_ERROR; } + /* Enable notch filter for LoRa 125kHz */ + if ((pkt_data.modulation == MOD_LORA) && (pkt_data.bandwidth == BW_125KHZ)) { + tx_notch_enable = true; + } + + /* Get the TX start delay to be applied for this TX */ + tx_start_delay = lgw_get_tx_start_delay(tx_notch_enable, pkt_data.bandwidth); + /* interpretation of TX power */ for (pow_index = txgain_lut.size-1; pow_index > 0; pow_index--) { if (txgain_lut.lut[pow_index].rf_power <= pkt_data.rf_power) { @@ -1443,7 +1460,7 @@ int lgw_send(struct lgw_pkt_tx_s pkt_data) { /* TX state machine must be triggered at (T0 - lgw_i_tx_start_delay_us) for packet to start being emitted at T0 */ if (pkt_data.tx_mode == TIMESTAMPED) { - count_trig = pkt_data.count_us - (uint32_t)lgw_i_tx_start_delay_us; + count_trig = pkt_data.count_us - (uint32_t)tx_start_delay; buff[3] = 0xFF & (count_trig >> 24); buff[4] = 0xFF & (count_trig >> 16); buff[5] = 0xFF & (count_trig >> 8); @@ -1519,10 +1536,12 @@ int lgw_send(struct lgw_pkt_tx_s pkt_data) { if (pkt_data.bandwidth == BW_500KHZ) { buff[0] |= 0x80; /* Set MSB bit to enlarge analog filter for 500kHz BW */ } - else if (pkt_data.bandwidth == BW_125KHZ){ - buff[0] |= 0x40; /* Set MSB-1 bit to enable digital filter for 125kHz BW */ - } + /* Set MSB-1 bit to enable digital filter if required */ + if (tx_notch_enable == true) { + DEBUG_MSG("INFO: Enabling TX notch filter\n"); + buff[0] |= 0x40; + } } 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 & pow_index); /* bit 4 is 1 -> FSK modulation */ @@ -1567,6 +1586,9 @@ int lgw_send(struct lgw_pkt_tx_s pkt_data) { return LGW_HAL_ERROR; } + /* Configure TX start delay based on TX notch filter */ + lgw_reg_w(LGW_TX_START_DELAY, tx_start_delay); + /* copy payload from user struct to buffer containing metadata */ memcpy((void *)(buff + payload_offset), (void *)(pkt_data.payload), pkt_data.size); @@ -1578,7 +1600,7 @@ int lgw_send(struct lgw_pkt_tx_s pkt_data) { lgw_reg_wb(LGW_TX_DATA_BUF_DATA, buff, transfer_size); DEBUG_ARRAY(i, transfer_size, buff); - x = lbt_is_channel_free(&pkt_data, &tx_allowed); + x = lbt_is_channel_free(&pkt_data, tx_start_delay, &tx_allowed); if (x != LGW_LBT_SUCCESS) { DEBUG_MSG("ERROR: Failed to check channel availability for TX\n"); return LGW_HAL_ERROR; diff --git a/libloragw/src/loragw_lbt.c b/libloragw/src/loragw_lbt.c index 98382bad..9c43521f 100644 --- a/libloragw/src/loragw_lbt.c +++ b/libloragw/src/loragw_lbt.c @@ -215,7 +215,7 @@ int lbt_start(void) { /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -int lbt_is_channel_free(struct lgw_pkt_tx_s * pkt_data, bool * tx_allowed) { +int lbt_is_channel_free(struct lgw_pkt_tx_s * pkt_data, uint16_t tx_start_delay, bool * tx_allowed) { int i; int32_t val; uint32_t tx_start_time = 0; @@ -255,7 +255,7 @@ int lbt_is_channel_free(struct lgw_pkt_tx_s * pkt_data, bool * tx_allowed) { break; case ON_GPS: DEBUG_MSG("tx_mode = ON_GPS\n"); - tx_start_time = (sx1301_time + (uint32_t)lgw_i_tx_start_delay_us + 1000000) & LBT_TIMESTAMP_MASK; + tx_start_time = (sx1301_time + (uint32_t)tx_start_delay + 1000000) & LBT_TIMESTAMP_MASK; break; case IMMEDIATE: DEBUG_MSG("ERROR: tx_mode IMMEDIATE is not supported when LBT is enabled\n"); @@ -267,7 +267,7 @@ int lbt_is_channel_free(struct lgw_pkt_tx_s * pkt_data, bool * tx_allowed) { /* Select LBT Channel corresponding to required TX frequency */ lbt_channel_decod_1 = -1; lbt_channel_decod_2 = -1; - if (pkt_data->bandwidth == BW_125KHZ){ + if (pkt_data->bandwidth == BW_125KHZ) { for (i=0; ifreq_hz, lbt_channel_cfg[i].freq_hz) == true) { DEBUG_PRINTF("LBT: select channel %d (%u Hz)\n", i, lbt_channel_cfg[i].freq_hz); diff --git a/libloragw/src/loragw_reg.c b/libloragw/src/loragw_reg.c index 43b4ba79..14e23cd4 100644 --- a/libloragw/src/loragw_reg.c +++ b/libloragw/src/loragw_reg.c @@ -389,7 +389,6 @@ const struct lgw_reg_s loregs[LGW_TOTALREGS] = { /* --- PRIVATE VARIABLES ---------------------------------------------------- */ static int lgw_regpage = -1; /*! keep the value of the register page selected */ -static enum lgw_brd_version_e lgw_i_brd_version = LGW_BRD_VERSION_UNKNOWN; /*! detected concentrator board version */ /* -------------------------------------------------------------------------- */ /* --- INTERNAL SHARED VARIABLES -------------------------------------------- */ @@ -532,11 +531,9 @@ int lgw_connect(bool spi_only, uint32_t tx_notch_freq) { /* We failed to read expected FPGA version, so let's assume there is no FPGA */ DEBUG_PRINTF("INFO: no FPGA detected or version not supported (v%u)\n", u); lgw_spi_mux_mode = LGW_SPI_MUX_MODE0; - lgw_i_brd_version = LGW_BRD_VERSION_1_0; } else { DEBUG_PRINTF("INFO: detected FPGA with SPI mux header (v%u)\n", u); lgw_spi_mux_mode = LGW_SPI_MUX_MODE1; - lgw_i_brd_version = LGW_BRD_VERSION_1_5; /* FPGA Soft Reset */ lgw_spi_w(lgw_spi_target, lgw_spi_mux_mode, LGW_SPI_MUX_TARGET_FPGA, 0, 1); lgw_spi_w(lgw_spi_target, lgw_spi_mux_mode, LGW_SPI_MUX_TARGET_FPGA, 0, 0); @@ -590,20 +587,6 @@ int lgw_disconnect(void) { /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -/* Get concentrator board version */ -int lgw_brd_version(enum lgw_brd_version_e * brd_version) { - if (lgw_spi_target == NULL) { - DEBUG_MSG("ERROR: CONCENTRATOR UNCONNECTED\n"); - return LGW_REG_ERROR; - } - - *brd_version = lgw_i_brd_version; - - return LGW_REG_SUCCESS; -} - -/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ - /* soft-reset function */ int lgw_soft_reset(void) { /* check if SPI is initialised */ diff --git a/readme.md b/readme.md index 14726992..cdfd8d1a 100644 --- a/readme.md +++ b/readme.md @@ -70,6 +70,12 @@ chip through GPIO, before starting any application using the concentrator. 4. Changelog ------------- +### v5.0.1 ### + +* HAL: Reworked the way the TX start delay is calculated, taking into account +the delay introduced by TX notch filter (when enabled) and the delay linked to +signal bandwidth separately. + ### v5.0.0 ### * HAL: Changed GPS module to get native GPS time (monotonic, no leap second).