Skip to content

Commit

Permalink
v5.0.1
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
mcoracin committed Apr 5, 2017
1 parent a0d4607 commit a955619
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 76 deletions.
2 changes: 1 addition & 1 deletion VERSION
@@ -1 +1 @@
5.0.0
5.0.1
11 changes: 11 additions & 0 deletions libloragw/inc/loragw_fpga.h
Expand Up @@ -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);

/**
Expand Down
2 changes: 1 addition & 1 deletion libloragw/inc/loragw_lbt.h
Expand Up @@ -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
Expand Down
12 changes: 0 additions & 12 deletions libloragw/inc/loragw_reg.h
Expand Up @@ -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 -------------------------------------------- */

Expand Down Expand Up @@ -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)
Expand Down
42 changes: 31 additions & 11 deletions libloragw/src/loragw_fpga.c
Expand Up @@ -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 ---------------------------------------------------- */

Expand All @@ -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)) {
Expand All @@ -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");
Expand All @@ -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;
Expand All @@ -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);
}
}

Expand Down
84 changes: 53 additions & 31 deletions libloragw/src/loragw_hal.c
Expand Up @@ -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;

Expand Down Expand Up @@ -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 ---------------------------------------- */

Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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 ------------------------------------------ */

Expand Down Expand Up @@ -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;

Expand All @@ -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();

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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);

Expand All @@ -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;
Expand Down
6 changes: 3 additions & 3 deletions libloragw/src/loragw_lbt.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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");
Expand All @@ -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; i<lbt_nb_active_channel; i++) {
if (is_equal_freq(pkt_data->freq_hz, lbt_channel_cfg[i].freq_hz) == true) {
DEBUG_PRINTF("LBT: select channel %d (%u Hz)\n", i, lbt_channel_cfg[i].freq_hz);
Expand Down
17 changes: 0 additions & 17 deletions libloragw/src/loragw_reg.c
Expand Up @@ -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 -------------------------------------------- */
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 */
Expand Down
6 changes: 6 additions & 0 deletions readme.md
Expand Up @@ -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).
Expand Down

0 comments on commit a955619

Please sign in to comment.