v1.0.3
* HAL: Fixed scheduled downlink time precision by taking the tx start delay into account. * HAL: Fixed timestamp correction calculation for BW250 & BW500 * HAL: Fixed possible buffer overflow in lgw_receive() function * HAL: Keep packet received in RX buffer when the buffer allocated to receive the packets is too small. Remaining packets will be fetched on the next lgw_receive calls (aligned on SX1301 behaviour).
This commit is contained in:
parent
df5cf56b74
commit
5942224602
10 changed files with 217 additions and 122 deletions
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
||||||
1.0.2
|
1.0.3
|
||||||
|
|
|
||||||
|
|
@ -350,28 +350,15 @@ void sx1302_arb_print_debug_stats(void);
|
||||||
uint16_t sx1302_lora_payload_crc(const uint8_t * data, uint8_t size);
|
uint16_t sx1302_lora_payload_crc(const uint8_t * data, uint8_t size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief TODO
|
@brief Get the number of packets available in rx_buffer and fetch data from ...
|
||||||
@param TODO
|
@brief ... the SX1302 if rx_buffer is empty.
|
||||||
@return TODO
|
@param nb_pkt A pointer to allocated memory to hold the number of packet fetched
|
||||||
*/
|
|
||||||
uint16_t sx1302_rx_buffer_read_ptr_addr(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
@brief TODO
|
|
||||||
@param TODO
|
|
||||||
@return TODO
|
|
||||||
*/
|
|
||||||
uint16_t sx1302_rx_buffer_write_ptr_addr(void);
|
|
||||||
|
|
||||||
/**
|
|
||||||
@brief Check if any data to be fetched from the SX1302 RX buffer and fetch it if any.
|
|
||||||
@param nb_bytes A pointer to allocated memory to hold the number of bytes fetched
|
|
||||||
@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
|
@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
|
||||||
*/
|
*/
|
||||||
int sx1302_fetch(uint16_t * nb_bytes);
|
int sx1302_fetch(uint8_t * nb_pkt);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief Parse and return the next packet available in the fetched RX buffer.
|
@brief Parse and return the next packet available in rx_buffer.
|
||||||
@param context Gateway configuration context
|
@param context Gateway configuration context
|
||||||
@param p The structure to get the packet parsed
|
@param p The structure to get the packet parsed
|
||||||
@return LGW_REG_SUCCESS if a packet could be parsed, LGW_REG_ERROR otherwise
|
@return LGW_REG_SUCCESS if a packet could be parsed, LGW_REG_ERROR otherwise
|
||||||
|
|
@ -384,9 +371,10 @@ int sx1302_parse(lgw_context_t * context, struct lgw_pkt_rx_s * p);
|
||||||
@param radio_type The type of radio for this RF chain
|
@param radio_type The type of radio for this RF chain
|
||||||
@param modulation The modulation used for the TX
|
@param modulation The modulation used for the TX
|
||||||
@param bandwidth The bandwidth used for the TX
|
@param bandwidth The bandwidth used for the TX
|
||||||
|
@param delay The TX start delay calculated and applied
|
||||||
@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
|
@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
|
||||||
*/
|
*/
|
||||||
int sx1302_tx_set_start_delay(uint8_t rf_chain, lgw_radio_type_t radio_type, uint8_t modulation, uint8_t bandwidth);
|
int sx1302_tx_set_start_delay(uint8_t rf_chain, lgw_radio_type_t radio_type, uint8_t modulation, uint8_t bandwidth, uint16_t * delay);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief Compute the offset to be applied on RSSI for temperature compensation
|
@brief Compute the offset to be applied on RSSI for temperature compensation
|
||||||
|
|
|
||||||
|
|
@ -72,36 +72,38 @@ typedef struct rx_buffer_s {
|
||||||
uint8_t buffer[4096]; /*!> byte array to hald the data fetched from the RX buffer */
|
uint8_t buffer[4096]; /*!> byte array to hald the data fetched from the RX buffer */
|
||||||
uint16_t buffer_size; /*!> The number of bytes currently stored in the buffer */
|
uint16_t buffer_size; /*!> The number of bytes currently stored in the buffer */
|
||||||
int buffer_index; /*!> Current parsing index in the buffer */
|
int buffer_index; /*!> Current parsing index in the buffer */
|
||||||
|
uint8_t buffer_pkt_nb;
|
||||||
} rx_buffer_t;
|
} rx_buffer_t;
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
|
/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief TODO
|
@brief Initialize the rx_buffer instance
|
||||||
@param TODO
|
@param self A pointer to a rx_buffer handler
|
||||||
@return TODO
|
@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
|
||||||
*/
|
*/
|
||||||
int rx_buffer_new(rx_buffer_t * self);
|
int rx_buffer_new(rx_buffer_t * self);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief TODO
|
@brief Reset the rx_buffer instance
|
||||||
@param TODO
|
@param self A pointer to a rx_buffer handler
|
||||||
@return TODO
|
@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
|
||||||
*/
|
*/
|
||||||
int rx_buffer_del(rx_buffer_t * self);
|
int rx_buffer_del(rx_buffer_t * self);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief TODO
|
@brief Fetch packets from the SX1302 internal RX buffer, and count packets available.
|
||||||
@param TODO
|
@param self A pointer to a rx_buffer handler
|
||||||
@return TODO
|
@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
|
||||||
*/
|
*/
|
||||||
int rx_buffer_fetch(rx_buffer_t * self);
|
int rx_buffer_fetch(rx_buffer_t * self);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief TODO
|
@brief Parse the rx_buffer and return the first packet available in the given structure.
|
||||||
@param TODO
|
@param self A pointer to a rx_buffer handler
|
||||||
@return TODO
|
@param pkt A pointer to the structure to receive the packet parsed
|
||||||
|
@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
|
||||||
*/
|
*/
|
||||||
int rx_buffer_pop(rx_buffer_t * self, rx_packet_t * pkt);
|
int rx_buffer_pop(rx_buffer_t * self, rx_packet_t * pkt);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,16 +54,16 @@ typedef struct timestamp_counter_s {
|
||||||
/* --- PUBLIC FUNCTIONS ----------------------------------------------------- */
|
/* --- PUBLIC FUNCTIONS ----------------------------------------------------- */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief TODO
|
@brief Initialize the timestamp_counter instance
|
||||||
@param TODO
|
@param self Pointer to the counter handler
|
||||||
@return TODO
|
@return N/A
|
||||||
*/
|
*/
|
||||||
void timestamp_counter_new(timestamp_counter_t * self);
|
void timestamp_counter_new(timestamp_counter_t * self);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief TODO
|
@brief Reset the timestamp_counter instance
|
||||||
@param TODO
|
@param self Pointer to the counter handler
|
||||||
@return TODO
|
@return N/A
|
||||||
*/
|
*/
|
||||||
void timestamp_counter_delete(timestamp_counter_t * self);
|
void timestamp_counter_delete(timestamp_counter_t * self);
|
||||||
|
|
||||||
|
|
@ -106,9 +106,14 @@ uint32_t timestamp_counter_get(timestamp_counter_t * self, bool pps);
|
||||||
uint32_t timestamp_counter_correction(int ifmod, uint8_t bandwidth, uint8_t datarate, uint8_t coderate, uint32_t crc_en, uint16_t payload_length);
|
uint32_t timestamp_counter_correction(int ifmod, uint8_t bandwidth, uint8_t datarate, uint8_t coderate, uint32_t crc_en, uint16_t payload_length);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief TODO
|
@brief Configure the SX1302 to output legacy timestamp or precision timestamp
|
||||||
@param TODO
|
@note Legacy timestamp gives a timestamp latched at the end of the packet
|
||||||
@return TODO
|
@note Precision timestamp gives a timestamp latched at the end of the header
|
||||||
|
@note and additionally supplies metrics every N symbols troughout the payload.
|
||||||
|
@param enable_precision_ts A boolean to enable precision timestamp output.
|
||||||
|
@param max_ts_metrics The number of timestamp metrics to be returned when precision timestamp is enabled
|
||||||
|
@param nb_symbols The sampling rate of timestamp metrics
|
||||||
|
@return LGW_REG_SUCCESS if success, LGW_REG_ERROR otherwise
|
||||||
*/
|
*/
|
||||||
int timestamp_counter_mode(bool enable_precision_ts, uint8_t max_ts_metrics, uint8_t nb_symbols);
|
int timestamp_counter_mode(bool enable_precision_ts, uint8_t max_ts_metrics, uint8_t nb_symbols);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ License: Revised BSD License, see LICENSE.TXT file include in the project
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h> /* symlink, unlink */
|
#include <unistd.h> /* symlink, unlink */
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
#include "loragw_reg.h"
|
#include "loragw_reg.h"
|
||||||
#include "loragw_hal.h"
|
#include "loragw_hal.h"
|
||||||
|
|
@ -451,7 +452,7 @@ int lgw_rxif_setconf(uint8_t if_chain, struct lgw_conf_rxif_s * conf) {
|
||||||
CONTEXT_FSK.sync_word_size = conf->sync_word_size;
|
CONTEXT_FSK.sync_word_size = conf->sync_word_size;
|
||||||
CONTEXT_FSK.sync_word = conf->sync_word;
|
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*llX\n", if_chain,
|
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].enable,
|
||||||
CONTEXT_IF_CHAIN[if_chain].freq_hz,
|
CONTEXT_IF_CHAIN[if_chain].freq_hz,
|
||||||
CONTEXT_FSK.bandwidth,
|
CONTEXT_FSK.bandwidth,
|
||||||
|
|
@ -772,9 +773,9 @@ int lgw_stop(void) {
|
||||||
|
|
||||||
int lgw_receive(uint8_t max_pkt, struct lgw_pkt_rx_s *pkt_data) {
|
int lgw_receive(uint8_t max_pkt, struct lgw_pkt_rx_s *pkt_data) {
|
||||||
int res;
|
int res;
|
||||||
uint16_t sz = 0;
|
uint8_t nb_pkt_fetched = 0;
|
||||||
uint16_t nb_pkt_found = 0;
|
uint16_t nb_pkt_found = 0;
|
||||||
uint16_t nb_pkt_dropped = 0;
|
uint16_t nb_pkt_left = 0;
|
||||||
float current_temperature, rssi_temperature_offset;
|
float current_temperature, rssi_temperature_offset;
|
||||||
|
|
||||||
/* Check that AGC/ARB firmwares are not corrupted, and update internal counter */
|
/* Check that AGC/ARB firmwares are not corrupted, and update internal counter */
|
||||||
|
|
@ -785,48 +786,46 @@ int lgw_receive(uint8_t max_pkt, struct lgw_pkt_rx_s *pkt_data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get packets from SX1302, if any */
|
/* Get packets from SX1302, if any */
|
||||||
res = sx1302_fetch(&sz);
|
res = sx1302_fetch(&nb_pkt_fetched);
|
||||||
if (res != LGW_REG_SUCCESS) {
|
if (res != LGW_REG_SUCCESS) {
|
||||||
printf("ERROR: failed to fetch packets from SX1302\n");
|
printf("ERROR: failed to fetch packets from SX1302\n");
|
||||||
return LGW_HAL_ERROR;
|
return LGW_HAL_ERROR;
|
||||||
}
|
}
|
||||||
if (sz == 0) {
|
if (nb_pkt_fetched == 0) {
|
||||||
return 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);
|
||||||
|
}
|
||||||
|
|
||||||
/* Get the current temperature for further RSSI compensation : TODO */
|
/* Apply RSSI temperature compensation */
|
||||||
res = stts751_get_temperature(ts_fd, ts_addr, ¤t_temperature);
|
res = stts751_get_temperature(ts_fd, ts_addr, ¤t_temperature);
|
||||||
if (res != LGW_I2C_SUCCESS) {
|
if (res != LGW_I2C_SUCCESS) {
|
||||||
printf("ERROR: failed to get current temperature\n");
|
printf("ERROR: failed to get current temperature\n");
|
||||||
return LGW_HAL_ERROR;
|
return LGW_HAL_ERROR;
|
||||||
}
|
}
|
||||||
DEBUG_PRINTF("INFO: current temperature is %f C\n", current_temperature);
|
|
||||||
|
|
||||||
/* Iterate on the RX buffer to get parsed packets */
|
/* Iterate on the RX buffer to get parsed packets */
|
||||||
res = LGW_REG_SUCCESS;
|
for (nb_pkt_found = 0; nb_pkt_found < ((nb_pkt_fetched <= max_pkt) ? nb_pkt_fetched : max_pkt); nb_pkt_found++) {
|
||||||
while ((res == LGW_REG_SUCCESS) && (nb_pkt_found <= max_pkt)) {
|
/* Get packet and move to next one */
|
||||||
res = sx1302_parse(&lgw_context, &pkt_data[nb_pkt_found]);
|
res = sx1302_parse(&lgw_context, &pkt_data[nb_pkt_found]);
|
||||||
if (res == LGW_REG_SUCCESS) {
|
if (res != LGW_REG_SUCCESS) {
|
||||||
/* we found a packet and parsed it */
|
printf("ERROR: failed to parse fetched packet %d, aborting...\n", nb_pkt_found);
|
||||||
if ((nb_pkt_found + 1) > max_pkt) {
|
return LGW_HAL_ERROR;
|
||||||
printf("WARNING: no space left, dropping packet\n");
|
|
||||||
nb_pkt_dropped += 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* 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;
|
|
||||||
/* Apply RSSI temperature compensation */
|
|
||||||
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\n", rssi_temperature_offset);
|
|
||||||
/* Next packet */
|
|
||||||
nb_pkt_found += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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 dropped:%u\n", nb_pkt_found, nb_pkt_dropped);
|
DEBUG_PRINTF("INFO: nb pkt found:%u left:%u\n", nb_pkt_found, nb_pkt_left);
|
||||||
|
|
||||||
return nb_pkt_found;
|
return nb_pkt_found;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -210,6 +210,9 @@ void sx1302_init(struct lgw_conf_timestamp_s *conf_ts) {
|
||||||
if (conf_ts != NULL) {
|
if (conf_ts != NULL) {
|
||||||
timestamp_counter_mode(conf_ts->enable_precision_ts, conf_ts->max_ts_metrics, conf_ts->nb_symbols);
|
timestamp_counter_mode(conf_ts->enable_precision_ts, conf_ts->max_ts_metrics, conf_ts->nb_symbols);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Initialize RX buffer */
|
||||||
|
rx_buffer_new(&rx_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||||
|
|
@ -1570,25 +1573,30 @@ int sx1302_arb_start(uint8_t version) {
|
||||||
|
|
||||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||||
|
|
||||||
int sx1302_fetch(uint16_t * nb_bytes) {
|
int sx1302_fetch(uint8_t * nb_pkt) {
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* Initialize RX buffer */
|
/* Fetch packets from sx1302 if no more left in RX buffer */
|
||||||
err = rx_buffer_new(&rx_buffer);
|
if (rx_buffer.buffer_pkt_nb == 0) {
|
||||||
if (err != LGW_REG_SUCCESS) {
|
/* Initialize RX buffer */
|
||||||
printf("ERROR: Failed to initialize RX buffer\n");
|
err = rx_buffer_new(&rx_buffer);
|
||||||
return LGW_REG_ERROR;
|
if (err != LGW_REG_SUCCESS) {
|
||||||
|
printf("ERROR: Failed to initialize RX buffer\n");
|
||||||
|
return LGW_REG_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fetch RX buffer if any data available */
|
||||||
|
err = rx_buffer_fetch(&rx_buffer);
|
||||||
|
if (err != LGW_REG_SUCCESS) {
|
||||||
|
printf("ERROR: Failed to fetch RX buffer\n");
|
||||||
|
return LGW_REG_ERROR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("Note: remaining %u packets in RX buffer, do not fetch sx1302 yet...\n", rx_buffer.buffer_pkt_nb);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fetch RX buffer if any data available */
|
/* Return the number of packet fetched */
|
||||||
err = rx_buffer_fetch(&rx_buffer);
|
*nb_pkt = rx_buffer.buffer_pkt_nb;
|
||||||
if (err != LGW_REG_SUCCESS) {
|
|
||||||
printf("ERROR: Failed to fetch RX buffer\n");
|
|
||||||
return LGW_REG_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return the number of bytes fetched */
|
|
||||||
*nb_bytes = rx_buffer.buffer_size;
|
|
||||||
|
|
||||||
return LGW_REG_SUCCESS;
|
return LGW_REG_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
@ -1833,7 +1841,7 @@ uint16_t sx1302_lora_payload_crc(const uint8_t * data, uint8_t size) {
|
||||||
|
|
||||||
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
|
||||||
|
|
||||||
int sx1302_tx_set_start_delay(uint8_t rf_chain, lgw_radio_type_t radio_type, uint8_t modulation, uint8_t bandwidth) {
|
int sx1302_tx_set_start_delay(uint8_t rf_chain, lgw_radio_type_t radio_type, uint8_t modulation, uint8_t bandwidth, uint16_t * delay) {
|
||||||
uint16_t tx_start_delay = TX_START_DELAY_DEFAULT * 32;
|
uint16_t tx_start_delay = TX_START_DELAY_DEFAULT * 32;
|
||||||
uint16_t radio_bw_delay = 0;
|
uint16_t radio_bw_delay = 0;
|
||||||
uint16_t filter_delay = 0;
|
uint16_t filter_delay = 0;
|
||||||
|
|
@ -1842,6 +1850,8 @@ int sx1302_tx_set_start_delay(uint8_t rf_chain, lgw_radio_type_t radio_type, uin
|
||||||
int32_t val;
|
int32_t val;
|
||||||
uint8_t chirp_low_pass = 0;
|
uint8_t chirp_low_pass = 0;
|
||||||
|
|
||||||
|
CHECK_NULL(delay);
|
||||||
|
|
||||||
/* Adjust with radio type and bandwidth */
|
/* Adjust with radio type and bandwidth */
|
||||||
switch (radio_type) {
|
switch (radio_type) {
|
||||||
case LGW_RADIO_TYPE_SX1250:
|
case LGW_RADIO_TYPE_SX1250:
|
||||||
|
|
@ -1896,6 +1906,9 @@ int sx1302_tx_set_start_delay(uint8_t rf_chain, lgw_radio_type_t radio_type, uin
|
||||||
lgw_reg_w(SX1302_REG_TX_TOP_TX_START_DELAY_MSB_TX_START_DELAY(rf_chain), (uint8_t)(tx_start_delay >> 8));
|
lgw_reg_w(SX1302_REG_TX_TOP_TX_START_DELAY_MSB_TX_START_DELAY(rf_chain), (uint8_t)(tx_start_delay >> 8));
|
||||||
lgw_reg_w(SX1302_REG_TX_TOP_TX_START_DELAY_LSB_TX_START_DELAY(rf_chain), (uint8_t)(tx_start_delay >> 0));
|
lgw_reg_w(SX1302_REG_TX_TOP_TX_START_DELAY_LSB_TX_START_DELAY(rf_chain), (uint8_t)(tx_start_delay >> 0));
|
||||||
|
|
||||||
|
/* return tx_start_delay */
|
||||||
|
*delay = tx_start_delay;
|
||||||
|
|
||||||
return LGW_REG_SUCCESS;
|
return LGW_REG_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2013,6 +2026,7 @@ int sx1302_send(lgw_radio_type_t radio_type, struct lgw_tx_gain_lut_s * tx_lut,
|
||||||
uint8_t pow_index;
|
uint8_t pow_index;
|
||||||
uint8_t mod_bw;
|
uint8_t mod_bw;
|
||||||
uint8_t pa_en;
|
uint8_t pa_en;
|
||||||
|
uint16_t tx_start_delay;
|
||||||
|
|
||||||
/* CHeck input parameters */
|
/* CHeck input parameters */
|
||||||
CHECK_NULL(tx_lut);
|
CHECK_NULL(tx_lut);
|
||||||
|
|
@ -2244,7 +2258,7 @@ int sx1302_send(lgw_radio_type_t radio_type, struct lgw_tx_gain_lut_s * tx_lut,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set TX start delay */
|
/* Set TX start delay */
|
||||||
sx1302_tx_set_start_delay(pkt_data->rf_chain, radio_type, pkt_data->modulation, pkt_data->bandwidth);
|
sx1302_tx_set_start_delay(pkt_data->rf_chain, radio_type, pkt_data->modulation, pkt_data->bandwidth, &tx_start_delay);
|
||||||
|
|
||||||
/* Write payload in transmit buffer */
|
/* Write payload in transmit buffer */
|
||||||
lgw_reg_w(SX1302_REG_TX_TOP_TX_CTRL_WRITE_BUFFER(pkt_data->rf_chain), 0x01);
|
lgw_reg_w(SX1302_REG_TX_TOP_TX_CTRL_WRITE_BUFFER(pkt_data->rf_chain), 0x01);
|
||||||
|
|
@ -2265,8 +2279,8 @@ int sx1302_send(lgw_radio_type_t radio_type, struct lgw_tx_gain_lut_s * tx_lut,
|
||||||
lgw_reg_w(SX1302_REG_TX_TOP_TX_TRIG_TX_TRIG_IMMEDIATE(pkt_data->rf_chain), 0x01);
|
lgw_reg_w(SX1302_REG_TX_TOP_TX_TRIG_TX_TRIG_IMMEDIATE(pkt_data->rf_chain), 0x01);
|
||||||
break;
|
break;
|
||||||
case TIMESTAMPED:
|
case TIMESTAMPED:
|
||||||
count_us = pkt_data->count_us * 32;
|
count_us = pkt_data->count_us * 32 - tx_start_delay;
|
||||||
DEBUG_PRINTF("--> programming trig delay at %u (%u)\n", pkt_data->count_us, count_us);
|
DEBUG_PRINTF("--> programming trig delay at %u (%u)\n", pkt_data->count_us - (tx_start_delay / 32), count_us);
|
||||||
|
|
||||||
lgw_reg_w(SX1302_REG_TX_TOP_TIMER_TRIG_BYTE0_TIMER_DELAYED_TRIG(pkt_data->rf_chain), (uint8_t)((count_us >> 0) & 0x000000FF));
|
lgw_reg_w(SX1302_REG_TX_TOP_TIMER_TRIG_BYTE0_TIMER_DELAYED_TRIG(pkt_data->rf_chain), (uint8_t)((count_us >> 0) & 0x000000FF));
|
||||||
lgw_reg_w(SX1302_REG_TX_TOP_TIMER_TRIG_BYTE1_TIMER_DELAYED_TRIG(pkt_data->rf_chain), (uint8_t)((count_us >> 8) & 0x000000FF));
|
lgw_reg_w(SX1302_REG_TX_TOP_TIMER_TRIG_BYTE1_TIMER_DELAYED_TRIG(pkt_data->rf_chain), (uint8_t)((count_us >> 8) & 0x000000FF));
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,7 @@ int rx_buffer_new(rx_buffer_t * self) {
|
||||||
memset(self->buffer, 0, sizeof self->buffer);
|
memset(self->buffer, 0, sizeof self->buffer);
|
||||||
self->buffer_size = 0;
|
self->buffer_size = 0;
|
||||||
self->buffer_index = 0;
|
self->buffer_index = 0;
|
||||||
|
self->buffer_pkt_nb = 0;
|
||||||
|
|
||||||
return LGW_REG_SUCCESS;
|
return LGW_REG_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
@ -121,6 +122,7 @@ int rx_buffer_del(rx_buffer_t * self) {
|
||||||
/* Reset index & size */
|
/* Reset index & size */
|
||||||
self->buffer_size = 0;
|
self->buffer_size = 0;
|
||||||
self->buffer_index = 0;
|
self->buffer_index = 0;
|
||||||
|
self->buffer_pkt_nb = 0;
|
||||||
|
|
||||||
return LGW_REG_SUCCESS;
|
return LGW_REG_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
@ -160,6 +162,29 @@ int rx_buffer_fetch(rx_buffer_t * self) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Parse buffer to get number of packet fetched */
|
||||||
|
uint8_t payload_len;
|
||||||
|
uint16_t next_pkt_idx;
|
||||||
|
int idx = 0;
|
||||||
|
while (idx < self->buffer_size) {
|
||||||
|
if ((self->buffer[idx] != SX1302_PKT_SYNCWORD_BYTE_0) || (self->buffer[idx + 1] != SX1302_PKT_SYNCWORD_BYTE_1)) {
|
||||||
|
printf("ERROR: syncword not found in rx_buffer\n");
|
||||||
|
return LGW_REG_ERROR;
|
||||||
|
}
|
||||||
|
/* One packet found in the buffer */
|
||||||
|
self->buffer_pkt_nb += 1;
|
||||||
|
|
||||||
|
/* Compute the number of bytes for thsi packet */
|
||||||
|
payload_len = SX1302_PKT_PAYLOAD_LENGTH(self->buffer, idx);
|
||||||
|
next_pkt_idx = SX1302_PKT_HEAD_METADATA +
|
||||||
|
payload_len +
|
||||||
|
SX1302_PKT_TAIL_METADATA +
|
||||||
|
(2 * SX1302_PKT_NUM_TS_METRICS(self->buffer, idx + payload_len));
|
||||||
|
|
||||||
|
/* Move to next packet */
|
||||||
|
idx += (int)next_pkt_idx;
|
||||||
|
}
|
||||||
|
|
||||||
/* Initialize the current buffer index to iterate on */
|
/* Initialize the current buffer index to iterate on */
|
||||||
self->buffer_index = 0;
|
self->buffer_index = 0;
|
||||||
|
|
||||||
|
|
@ -295,9 +320,12 @@ int rx_buffer_pop(rx_buffer_t * self, rx_packet_t * pkt) {
|
||||||
/* Parse & copy payload in packet struct */
|
/* Parse & copy payload in packet struct */
|
||||||
memcpy((void *)pkt->payload, (void *)(&(self->buffer[self->buffer_index + SX1302_PKT_HEAD_METADATA])), pkt->rxbytenb_modem);
|
memcpy((void *)pkt->payload, (void *)(&(self->buffer[self->buffer_index + SX1302_PKT_HEAD_METADATA])), pkt->rxbytenb_modem);
|
||||||
|
|
||||||
/* move buffer index toward next message */
|
/* Move buffer index toward next message */
|
||||||
self->buffer_index += (SX1302_PKT_HEAD_METADATA + pkt->rxbytenb_modem + SX1302_PKT_TAIL_METADATA + (2 * pkt->num_ts_metrics_stored));
|
self->buffer_index += (SX1302_PKT_HEAD_METADATA + pkt->rxbytenb_modem + SX1302_PKT_TAIL_METADATA + (2 * pkt->num_ts_metrics_stored));
|
||||||
|
|
||||||
|
/* Update the umber of packets currently stored in the rx_buffer */
|
||||||
|
self->buffer_pkt_nb -= 1;
|
||||||
|
|
||||||
return LGW_REG_SUCCESS;
|
return LGW_REG_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -191,42 +191,31 @@ int timestamp_counter_mode(bool enable_precision_ts, uint8_t max_ts_metrics, uin
|
||||||
|
|
||||||
uint32_t timestamp_counter_correction(int ifmod, uint8_t bandwidth, uint8_t datarate, uint8_t coderate, uint32_t crc_en, uint16_t payload_length) {
|
uint32_t timestamp_counter_correction(int ifmod, uint8_t bandwidth, uint8_t datarate, uint8_t coderate, uint32_t crc_en, uint16_t payload_length) {
|
||||||
int32_t val;
|
int32_t val;
|
||||||
uint32_t sf = (uint32_t)datarate, cr = (uint32_t)coderate, bw_pow, ppm;
|
uint32_t sf = (uint32_t)datarate, cr = (uint32_t)coderate, bw_pow;
|
||||||
uint32_t clk_period;
|
uint32_t clk_period;
|
||||||
uint32_t nb_nibble, nb_nibble_in_hdr, nb_nibble_in_last_block;
|
uint32_t nb_nibble, nb_nibble_in_hdr, nb_nibble_in_last_block;
|
||||||
uint32_t dft_peak_en, nb_iter;
|
uint32_t dft_peak_en, nb_iter;
|
||||||
uint32_t demap_delay, decode_delay, fft_delay_state3, fft_delay, delay_x;
|
uint32_t demap_delay, decode_delay, fft_delay_state3, fft_delay, delay_x;
|
||||||
uint32_t timestamp_correction;
|
uint32_t timestamp_correction;
|
||||||
|
uint32_t ppm = SET_PPM_ON(bandwidth, datarate) ? 1 : 0;
|
||||||
|
|
||||||
/* determine if 'PPM mode' is on */
|
|
||||||
if (SET_PPM_ON(bandwidth, datarate)) {
|
|
||||||
ppm = 1;
|
|
||||||
} else {
|
|
||||||
ppm = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* timestamp correction code, base delay */
|
|
||||||
switch (bandwidth)
|
switch (bandwidth)
|
||||||
{
|
{
|
||||||
case BW_125KHZ:
|
case BW_125KHZ:
|
||||||
bw_pow = 1;
|
bw_pow = 1;
|
||||||
delay_x = 16000000 / bw_pow + 2031250;
|
|
||||||
break;
|
break;
|
||||||
case BW_250KHZ:
|
case BW_250KHZ:
|
||||||
bw_pow = 2;
|
bw_pow = 2;
|
||||||
delay_x = 16000000 / bw_pow + 2031250;
|
|
||||||
break;
|
break;
|
||||||
case BW_500KHZ:
|
case BW_500KHZ:
|
||||||
bw_pow = 4;
|
bw_pow = 4;
|
||||||
delay_x = 16000000 / bw_pow + 2031250;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", bandwidth);
|
DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", bandwidth);
|
||||||
delay_x = 0;
|
return 0;
|
||||||
bw_pow = 0;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
clk_period = 250000;
|
clk_period = 250000 / bw_pow;
|
||||||
|
delay_x = 16000000 / bw_pow + 2031250;
|
||||||
|
|
||||||
nb_nibble = (payload_length + 2 * crc_en) * 2 + 5;
|
nb_nibble = (payload_length + 2 * crc_en) * 2 + 5;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,11 +69,13 @@ void usage(void) {
|
||||||
//printf("Library version information: %s\n", lgw_version_info());
|
//printf("Library version information: %s\n", lgw_version_info());
|
||||||
printf( "Available options:\n");
|
printf( "Available options:\n");
|
||||||
printf( " -h print this help\n");
|
printf( " -h print this help\n");
|
||||||
printf( " -k <uint> Concentrator clock source (Radio A or Radio B) [0..1]\n");
|
printf( " -k <uint> Concentrator clock source (Radio A or Radio B) [0..1]\n");
|
||||||
printf( " -r <uint> Radio type (1255, 1257, 1250)\n");
|
printf( " -r <uint> Radio type (1255, 1257, 1250)\n");
|
||||||
printf( " -a <float> Radio A RX frequency in MHz\n");
|
printf( " -a <float> Radio A RX frequency in MHz\n");
|
||||||
printf( " -b <float> Radio B RX frequency in MHz\n");
|
printf( " -b <float> Radio B RX frequency in MHz\n");
|
||||||
printf( " -n <uint> number of packet received with CRC OK for each HAL start/stop loop\n");
|
printf( " -n <uint> Number of packet received with CRC OK for each HAL start/stop loop\n");
|
||||||
|
printf( " -z <uint> Size of the RX packet array to be passed to lgw_receive()\n");
|
||||||
|
printf( " -m <uint> Channel frequency plan mode [0:LoRaWAN-like, 1:Same frequency for all channels (-400000Hz on RF0)]\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
@ -94,31 +96,47 @@ int main(int argc, char **argv)
|
||||||
unsigned int arg_u;
|
unsigned int arg_u;
|
||||||
uint8_t clocksource = 0;
|
uint8_t clocksource = 0;
|
||||||
lgw_radio_type_t radio_type = LGW_RADIO_TYPE_NONE;
|
lgw_radio_type_t radio_type = LGW_RADIO_TYPE_NONE;
|
||||||
|
uint8_t max_rx_pkt = 16;
|
||||||
|
|
||||||
struct lgw_conf_board_s boardconf;
|
struct lgw_conf_board_s boardconf;
|
||||||
struct lgw_conf_rxrf_s rfconf;
|
struct lgw_conf_rxrf_s rfconf;
|
||||||
struct lgw_conf_rxif_s ifconf;
|
struct lgw_conf_rxif_s ifconf;
|
||||||
struct lgw_pkt_rx_s rxpkt[16];
|
|
||||||
|
|
||||||
unsigned long nb_pkt_crc_ok = 0, nb_loop = 1, cnt_loop;
|
unsigned long nb_pkt_crc_ok = 0, nb_loop = 0, cnt_loop;
|
||||||
int nb_pkt;
|
int nb_pkt;
|
||||||
|
|
||||||
const int32_t channel_if[9] = {
|
uint8_t channel_mode = 0; /* LoRaWAN-like */
|
||||||
|
|
||||||
|
const int32_t channel_if_mode0[9] = {
|
||||||
-400000,
|
-400000,
|
||||||
-200000,
|
-200000,
|
||||||
0,
|
0,
|
||||||
-400000,
|
-400000,
|
||||||
-200000,
|
-200000,
|
||||||
0,
|
0,
|
||||||
200000,
|
-400000,
|
||||||
400000,
|
-200000,
|
||||||
-200000 /* lora service */
|
-400000 /* lora service */
|
||||||
};
|
};
|
||||||
|
|
||||||
const uint8_t channel_rfchain[9] = { 1, 1, 1, 0, 0, 0, 0, 0, 1 };
|
const int32_t channel_if_mode1[9] = {
|
||||||
|
-400000,
|
||||||
|
-400000,
|
||||||
|
-400000,
|
||||||
|
-400000,
|
||||||
|
-400000,
|
||||||
|
-400000,
|
||||||
|
-400000,
|
||||||
|
-400000,
|
||||||
|
-400000 /* lora service */
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t channel_rfchain_mode0[9] = { 1, 1, 1, 0, 0, 0, 0, 0, 1 };
|
||||||
|
|
||||||
|
const uint8_t channel_rfchain_mode1[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||||
|
|
||||||
/* parse command line options */
|
/* parse command line options */
|
||||||
while ((i = getopt (argc, argv, "ha:b:k:r:n:")) != -1) {
|
while ((i = getopt (argc, argv, "ha:b:k:r:n:z:m:")) != -1) {
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case 'h':
|
case 'h':
|
||||||
usage();
|
usage();
|
||||||
|
|
@ -179,6 +197,24 @@ int main(int argc, char **argv)
|
||||||
nb_loop = arg_u;
|
nb_loop = arg_u;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'z': /* <uint> Size of the RX packet array to be passed to lgw_receive() */
|
||||||
|
i = sscanf(optarg, "%u", &arg_u);
|
||||||
|
if (i != 1) {
|
||||||
|
printf("ERROR: argument parsing of -z argument. Use -h to print help\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
} else {
|
||||||
|
max_rx_pkt = arg_u;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
i = sscanf(optarg, "%u", &arg_u);
|
||||||
|
if ((i != 1) || (arg_u > 1)) {
|
||||||
|
printf("ERROR: argument parsing of -m argument. Use -h to print help\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
} else {
|
||||||
|
channel_mode = arg_u;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
printf("ERROR: argument parsing\n");
|
printf("ERROR: argument parsing\n");
|
||||||
usage();
|
usage();
|
||||||
|
|
@ -231,10 +267,18 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
/* set configuration for LoRa multi-SF channels (bandwidth cannot be set) */
|
/* set configuration for LoRa multi-SF channels (bandwidth cannot be set) */
|
||||||
memset(&ifconf, 0, sizeof(ifconf));
|
memset(&ifconf, 0, sizeof(ifconf));
|
||||||
for (i = 0; i < 9; i++) {
|
for (i = 0; i < 8; i++) {
|
||||||
ifconf.enable = true;
|
ifconf.enable = true;
|
||||||
ifconf.rf_chain = channel_rfchain[i];
|
if (channel_mode == 0) {
|
||||||
ifconf.freq_hz = channel_if[i];
|
ifconf.rf_chain = channel_rfchain_mode0[i];
|
||||||
|
ifconf.freq_hz = channel_if_mode0[i];
|
||||||
|
} else if (channel_mode == 1) {
|
||||||
|
ifconf.rf_chain = channel_rfchain_mode1[i];
|
||||||
|
ifconf.freq_hz = channel_if_mode1[i];
|
||||||
|
} else {
|
||||||
|
printf("ERROR: channel mode not supported\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
ifconf.datarate = DR_LORA_SF7;
|
ifconf.datarate = DR_LORA_SF7;
|
||||||
if (lgw_rxif_setconf(i, &ifconf) != LGW_HAL_SUCCESS) {
|
if (lgw_rxif_setconf(i, &ifconf) != LGW_HAL_SUCCESS) {
|
||||||
printf("ERROR: failed to configure rxif %d\n", i);
|
printf("ERROR: failed to configure rxif %d\n", i);
|
||||||
|
|
@ -242,6 +286,22 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* set configuration for LoRa Service channel */
|
||||||
|
memset(&ifconf, 0, sizeof(ifconf));
|
||||||
|
ifconf.rf_chain = channel_rfchain_mode0[i];
|
||||||
|
ifconf.freq_hz = channel_if_mode0[i];
|
||||||
|
ifconf.datarate = DR_LORA_SF7;
|
||||||
|
ifconf.bandwidth = BW_250KHZ;
|
||||||
|
if (lgw_rxif_setconf(8, &ifconf) != LGW_HAL_SUCCESS) {
|
||||||
|
printf("ERROR: failed to configure rxif for LoRa service channel\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set the buffer size to hold received packets */
|
||||||
|
struct lgw_pkt_rx_s rxpkt[max_rx_pkt];
|
||||||
|
printf("INFO: rxpkt buffer size is set to %u\n", max_rx_pkt);
|
||||||
|
printf("INFO: Select channel mode %u\n", channel_mode);
|
||||||
|
|
||||||
/* Loop until user quits */
|
/* Loop until user quits */
|
||||||
cnt_loop = 0;
|
cnt_loop = 0;
|
||||||
while( (quit_sig != 1) && (exit_sig != 1) )
|
while( (quit_sig != 1) && (exit_sig != 1) )
|
||||||
|
|
@ -264,14 +324,13 @@ int main(int argc, char **argv)
|
||||||
/* Loop until we have enough packets with CRC OK */
|
/* Loop until we have enough packets with CRC OK */
|
||||||
printf("Waiting for packets...\n");
|
printf("Waiting for packets...\n");
|
||||||
nb_pkt_crc_ok = 0;
|
nb_pkt_crc_ok = 0;
|
||||||
while ((nb_pkt_crc_ok < nb_loop) && (quit_sig != 1) && (exit_sig != 1)) {
|
while (((nb_pkt_crc_ok < nb_loop) || nb_loop == 0) && (quit_sig != 1) && (exit_sig != 1)) {
|
||||||
/* fetch N packets */
|
/* fetch N packets */
|
||||||
nb_pkt = lgw_receive(ARRAY_SIZE(rxpkt), rxpkt);
|
nb_pkt = lgw_receive(ARRAY_SIZE(rxpkt), rxpkt);
|
||||||
|
|
||||||
if (nb_pkt == 0) {
|
if (nb_pkt == 0) {
|
||||||
wait_ms(10);
|
wait_ms(10);
|
||||||
} else {
|
} else {
|
||||||
printf("Received %d packets\n", nb_pkt);
|
|
||||||
for (i = 0; i < nb_pkt; i++) {
|
for (i = 0; i < nb_pkt; i++) {
|
||||||
if (rxpkt[i].status == STAT_CRC_OK) {
|
if (rxpkt[i].status == STAT_CRC_OK) {
|
||||||
nb_pkt_crc_ok += 1;
|
nb_pkt_crc_ok += 1;
|
||||||
|
|
@ -294,6 +353,7 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
printf("Received %d packets (total:%lu)\n", nb_pkt, nb_pkt_crc_ok);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
10
readme.md
10
readme.md
|
|
@ -161,6 +161,16 @@ found in the `libtools` directory.
|
||||||
|
|
||||||
## 6. Changelog
|
## 6. Changelog
|
||||||
|
|
||||||
|
### v1.0.3 ###
|
||||||
|
|
||||||
|
* HAL: Fixed scheduled downlink time precision by taking the tx start delay into
|
||||||
|
account.
|
||||||
|
* HAL: Fixed timestamp correction calculation for BW250 & BW500
|
||||||
|
* HAL: Fixed possible buffer overflow in lgw_receive() function
|
||||||
|
* HAL: Keep packet received in RX buffer when the buffer allocated to receive
|
||||||
|
the packets is too small. Remaining packets will be fetched on the next
|
||||||
|
lgw_receive calls (aligned on SX1301 behaviour).
|
||||||
|
|
||||||
### v1.0.2 ###
|
### v1.0.2 ###
|
||||||
|
|
||||||
* Fixed compilation warnings reported by latest versions of GCC
|
* Fixed compilation warnings reported by latest versions of GCC
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue