Rewrite BladeRF's device_init()

- Add more sampling rates to support, e.g., 40MHz in 5G
- Allocate memory only at end to avoid memory leaks in case of failure
- Group recurring configuration functionality in configure_channel() to
  reduced code duplication and uniform output
- Read maximum TX gain to set maximum automatically, and analogous to
  USRP radio lib
- Check if BladeRF config (buffer size, num transfers, ...) fulfills
  requirements as specified in documentation [1]
- Set BladeRF logging early to see BladeRF output

[1] https://www.nuand.com/bladeRF-doc/libbladeRF/v2.6.0/group___f_n___s_t_r_e_a_m_i_n_g___a_s_y_n_c.html#ga72752f2a047b95544e7686596a409abd

Co-authored-by: Brice Robert <robert@eurecom.fr>
Closes: #845
This commit is contained in:
Robert Schmidt
2026-02-11 18:37:45 +01:00
co-authored by Brice Robert
parent f14aa8283c
commit 792e1ed7d9
+188 -148
View File
@@ -95,6 +95,23 @@ int brf_error(int status);
const bladerf_format format = BLADERF_FORMAT_SC16_Q11_META;
static const char *ch_dir(bladerf_channel ch)
{
switch (ch) {
case BLADERF_CHANNEL_RX(0):
return "RX0";
case BLADERF_CHANNEL_RX(1):
return "RX1";
case BLADERF_CHANNEL_TX(0):
return "TX0";
case BLADERF_CHANNEL_TX(1):
return "TX1";
default:
return "unknown";
}
return "unknown";
}
/*! \brief Start BladeRF
* \param device the hardware to use
* \returns 0 on success
@@ -333,6 +350,40 @@ int trx_brf_write_init(openair0_device_t *device)
return 0;
}
typedef struct channel_config {
bladerf_channel channel;
unsigned int frequency;
unsigned int sample_rate;
unsigned int bandwidth;
int gain;
} channel_config_t;
static int configure_channel(struct bladerf *dev, channel_config_t *c)
{
int status;
unsigned int actual_value = 0;
const char *dir = ch_dir(c->channel);
status = bladerf_set_frequency(dev, c->channel, c->frequency);
BLADERF_CHECK(status == 0, "Set %s frequency %u", dir, c->frequency);
status = bladerf_set_sample_rate(dev, c->channel, c->sample_rate, &actual_value);
BLADERF_CHECK(status == 0, "Set %s sample rate %u (is %u)", dir, c->sample_rate, actual_value);
status = bladerf_set_bandwidth(dev, c->channel, c->bandwidth, &actual_value);
BLADERF_CHECK(status == 0, "Set %s bandwidth %u (is %u)", dir, c->bandwidth, actual_value);
status = bladerf_set_gain(dev, c->channel, c->gain);
BLADERF_CHECK(status == 0, "Set %s gain %u", dir, c->gain);
bladerf_gain g;
status = bladerf_get_gain(dev, c->channel, &g);
BLADERF_CHECK(status == 0, "Get %s gain: %u", dir, g);
return 0;
}
/*! \brief Initialize Openair BLADERF target. It returns 0 if OK
* \param device the hardware to use
* \param openair0_cfg RF frontend parameters set by application
@@ -340,167 +391,156 @@ int trx_brf_write_init(openair0_device_t *device)
*/
int device_init(openair0_device_t *device, openair0_config_t *openair0_cfg)
{
int status;
brf_state_t *brf = (brf_state_t*)malloc(sizeof(brf_state_t));
memset(brf, 0, sizeof(brf_state_t));
/* device specific */
//openair0_cfg->txlaunch_wait = 1;//manage when TX processing is triggered
//openair0_cfg->txlaunch_wait_slotcount = 1; //manage when TX processing is triggered
int status;
brf_state_t brf = {0};
switch ((long) openair0_cfg->sample_rate) {
case 46080000:
openair0_cfg->samples_per_packet = 8192;
openair0_cfg->tx_sample_advance = 0;
brf.num_buffers = 128;
brf.num_transfers = 32;
brf.rx_timeout_ms = 2000;
break;
// init required params
switch ((int)openair0_cfg->sample_rate) {
case 30720000:
openair0_cfg->samples_per_packet = 2048;
openair0_cfg->tx_sample_advance = 0;
break;
openair0_cfg->samples_per_packet = 4096;
openair0_cfg->tx_sample_advance = 0;
brf.num_buffers = 128;
brf.num_transfers = 32;
brf.rx_timeout_ms = 2000;
break;
case 23040000:
openair0_cfg->samples_per_packet = 2048;
openair0_cfg->tx_sample_advance = 0;
brf.num_buffers = 64;
brf.num_transfers = 16;
brf.rx_timeout_ms = 2000;
break;
case 15360000:
openair0_cfg->samples_per_packet = 2048;
openair0_cfg->tx_sample_advance = 0;
break;
openair0_cfg->samples_per_packet = 2048;
openair0_cfg->tx_sample_advance = 0;
brf.num_buffers = 64;
brf.num_transfers = 16;
brf.rx_timeout_ms = 2000;
break;
case 11520000:
openair0_cfg->samples_per_packet = 2048;
openair0_cfg->tx_sample_advance = 0;
brf.num_buffers = 64;
brf.num_transfers = 16;
brf.rx_timeout_ms = 2000;
break;
case 7680000:
openair0_cfg->samples_per_packet = 1024;
openair0_cfg->tx_sample_advance = 0;
break;
openair0_cfg->samples_per_packet = 1024;
openair0_cfg->tx_sample_advance = 0;
brf.num_buffers = 32;
brf.num_transfers = 16;
brf.rx_timeout_ms = 2000;
break;
case 1920000:
openair0_cfg->samples_per_packet = 256;
openair0_cfg->tx_sample_advance = 50;
break;
openair0_cfg->samples_per_packet = 256;
openair0_cfg->tx_sample_advance = 50;
brf.num_buffers = 128;
brf.num_transfers = 16;
brf.rx_timeout_ms = 2000;
break;
default:
printf("Error: unknown sampling rate %f\n",openair0_cfg->sample_rate);
exit(-1);
break;
LOG_E(HW, "Error: unknown sampling rate %f\n", openair0_cfg->sample_rate);
return -1;
break;
}
brf.tx_timeout_ms = 2000;
brf.buffer_size = (unsigned int)openair0_cfg->samples_per_packet;
brf.sample_rate = (unsigned int)openair0_cfg->sample_rate;
float rxterm = brf.num_transfers * brf.buffer_size * 1000.0 / brf.rx_timeout_ms;
float txterm = brf.num_transfers * brf.buffer_size * 1000.0 / brf.tx_timeout_ms;
LOG_I(HW,
"sample rate %d trnsfers %d timeout rx %d tx %d buffer size %d (rx %f, tx %f)\n",
brf.sample_rate,
brf.num_transfers,
brf.rx_timeout_ms,
brf.tx_timeout_ms,
brf.buffer_size,
rxterm,
txterm);
DevAssert(brf.sample_rate > txterm * 1.25); // see doc on async interface
DevAssert(brf.sample_rate > rxterm * 1.25);
memset(&brf.meta_rx, 0, sizeof(brf.meta_rx));
memset(&brf.meta_tx, 0, sizeof(brf.meta_tx));
// set this to BLADERF_LOG_LEVEL_VERBOSE for more detailed BladeRF info
bladerf_log_set_verbosity(BLADERF_LOG_LEVEL_INFO);
status = bladerf_open(&brf.dev, openair0_cfg->sdr_addrs);
BLADERF_CHECK(status == 0, "Init BladeRF device '%s'", openair0_cfg->sdr_addrs);
if (bladerf_device_speed(brf.dev) != BLADERF_DEVICE_SPEED_SUPER) {
LOG_E(HW, "Device does not operate at max speed, change the USB port\n");
return -1;
}
// The number of buffers to use in the underlying data stream
brf->num_buffers = 128;
// the size of the underlying stream buffers, in samples
brf->buffer_size = (unsigned int) openair0_cfg->samples_per_packet;//*sizeof(int32_t); // buffer size = 4096 for sample_len of 1024
brf->num_transfers = 16;
brf->rx_timeout_ms = 0;
brf->tx_timeout_ms = 0;
brf->sample_rate=(unsigned int)openair0_cfg->sample_rate;
/** [Forcing Tuning Mode to FPGA] */
const bladerf_tuning_mode tMode = BLADERF_TUNING_MODE_FPGA;
status = bladerf_set_tuning_mode(brf.dev, tMode);
BLADERF_CHECK(status == 0, "Set tuning mode FPGA");
memset(&brf->meta_rx, 0, sizeof(brf->meta_rx));
memset(&brf->meta_tx, 0, sizeof(brf->meta_tx));
status = bladerf_set_gain_mode(brf.dev, BLADERF_CHANNEL_RX(0), BLADERF_GAIN_MGC);
BLADERF_CHECK(status == 0, "Disable AGC");
printf("\n[BRF] sampling_rate %u, num_buffers %u, buffer_size %u, num transfer %u, timeout_ms (rx %u, tx %u)\n",
brf->sample_rate, brf->num_buffers, brf->buffer_size,brf->num_transfers, brf->rx_timeout_ms, brf->tx_timeout_ms);
channel_config_t rx_chan = {
.channel = BLADERF_CHANNEL_RX(0),
.frequency = openair0_cfg->rx_freq[0],
.sample_rate = openair0_cfg->sample_rate,
.bandwidth = openair0_cfg->rx_bw,
.gain = openair0_cfg->rx_gain[0],
};
configure_channel(brf.dev, &rx_chan);
if ((status=bladerf_open(&brf->dev, "")) != 0 ) {
fprintf(stderr,"Failed to open brf device: %s\n",bladerf_strerror(status));
brf_error(status);
}
printf("[BRF] init dev %p\n", brf->dev);
switch(bladerf_device_speed(brf->dev)) {
case BLADERF_DEVICE_SPEED_SUPER:
printf("[BRF] Device operates at max speed\n");
break;
default:
printf("[BRF] Device does not operates at max speed, change the USB port\n");
brf_error(BLADERF_ERR_UNSUPPORTED);
}
// RX
// Example of CLI output: RX Frequency: 2539999999Hz
// This is a hack. The USRP library currently does max_gain-tx_gain (tx_gain
// is the attenuation, so completely illogical), but let's keep what users
// would expect by doing the same. Existing configs can then be reused.
// Note also that the doc says that get_gain_range() should be called after
// setting the frequency, but the gain should normally come from outside, so
// be set by user and independent of the exact frequency.
const struct bladerf_range *g = NULL;
status = bladerf_get_gain_range(brf.dev, BLADERF_CHANNEL_TX(0), &g);
BLADERF_CHECK(status == 0 && g != NULL, "Get TX0 gain range");
channel_config_t tx_chan = {
.channel = BLADERF_CHANNEL_TX(0),
.frequency = openair0_cfg->tx_freq[0],
.sample_rate = openair0_cfg->sample_rate,
.bandwidth = openair0_cfg->tx_bw,
.gain = g->max - openair0_cfg->tx_gain[0], // see comment above
};
configure_channel(brf.dev, &tx_chan);
LOG_I(HW, "BLADERF: Initializing device done\n");
device->type = BLADERF_DEV;
device->trx_start_func = trx_brf_start;
device->trx_end_func = trx_brf_end;
device->trx_read_func = trx_brf_read;
device->trx_write_func = trx_brf_write;
device->trx_get_stats_func = trx_brf_get_stats;
device->trx_reset_stats_func = trx_brf_reset_stats;
device->trx_stop_func = trx_brf_stop;
device->trx_set_freq_func = trx_brf_set_freq;
device->trx_set_gains_func = trx_brf_set_gains;
device->trx_write_init = trx_brf_write_init;
device->openair0_cfg = openair0_cfg;
device->priv = malloc_or_fail(sizeof(brf_state_t));
*(brf_state_t *)device->priv = brf;
if ((status=bladerf_set_gain_mode(brf->dev, BLADERF_MODULE_RX, BLADERF_GAIN_MGC))) {
fprintf(stderr, "[BRF] Failed to disable AGC\n");
brf_error(status);
}
if ((status=bladerf_set_frequency(brf->dev, BLADERF_MODULE_RX, (unsigned int) openair0_cfg->rx_freq[0])) != 0) {
fprintf(stderr,"Failed to set RX frequency: %s\n",bladerf_strerror(status));
brf_error(status);
} else
printf("[BRF] set RX frequency to %u\n",(unsigned int)openair0_cfg->rx_freq[0]);
unsigned int actual_value=0;
if ((status=bladerf_set_sample_rate(brf->dev, BLADERF_MODULE_RX, (unsigned int) openair0_cfg->sample_rate, &actual_value)) != 0) {
fprintf(stderr,"Failed to set RX sample rate: %s\n", bladerf_strerror(status));
brf_error(status);
} else
printf("[BRF] set RX sample rate to %u, %u\n", (unsigned int) openair0_cfg->sample_rate, actual_value);
if ((status=bladerf_set_bandwidth(brf->dev, BLADERF_MODULE_RX, (unsigned int) openair0_cfg->rx_bw*2, &actual_value)) != 0) {
fprintf(stderr,"Failed to set RX bandwidth: %s\n", bladerf_strerror(status));
brf_error(status);
} else
printf("[BRF] set RX bandwidth to %u, %u\n",(unsigned int)openair0_cfg->rx_bw*2, actual_value);
if ((status=bladerf_set_gain(brf->dev, BLADERF_MODULE_RX, (int) openair0_cfg->rx_gain[0]-openair0_cfg[0].rx_gain_offset[0])) != 0) {
fprintf(stderr,"Failed to set RX gain: %s\n",bladerf_strerror(status));
brf_error(status);
} else
printf("[BRF] set RX gain to %d (%d)\n",(int)(openair0_cfg->rx_gain[0]-openair0_cfg[0].rx_gain_offset[0]),(int)openair0_cfg[0].rx_gain_offset[0]);
// TX
if ((status=bladerf_set_frequency(brf->dev, BLADERF_MODULE_TX, (unsigned int) openair0_cfg->tx_freq[0])) != 0) {
fprintf(stderr,"Failed to set TX frequency: %s\n",bladerf_strerror(status));
brf_error(status);
} else
printf("[BRF] set TX Frequency to %u\n", (unsigned int) openair0_cfg->tx_freq[0]);
if ((status=bladerf_set_sample_rate(brf->dev, BLADERF_MODULE_TX, (unsigned int) openair0_cfg->sample_rate, NULL)) != 0) {
fprintf(stderr,"Failed to set TX sample rate: %s\n", bladerf_strerror(status));
brf_error(status);
} else
printf("[BRF] set TX sampling rate to %u \n", (unsigned int) openair0_cfg->sample_rate);
if ((status=bladerf_set_bandwidth(brf->dev, BLADERF_MODULE_TX,(unsigned int)openair0_cfg->tx_bw*2, NULL)) != 0) {
fprintf(stderr, "Failed to set TX bandwidth: %s\n", bladerf_strerror(status));
brf_error(status);
} else
printf("[BRF] set TX bandwidth to %u \n", (unsigned int) openair0_cfg->tx_bw*2);
if ((status=bladerf_set_gain(brf->dev, BLADERF_MODULE_TX, (int) openair0_cfg->tx_gain[0])) != 0) {
fprintf(stderr,"Failed to set TX gain: %s\n",bladerf_strerror(status));
brf_error(status);
} else
printf("[BRF] set the TX gain to %d\n", (int)openair0_cfg->tx_gain[0]);
/* set log to info, available log levels are:
* - BLADERF_LOG_LEVEL_VERBOSE
* - BLADERF_LOG_LEVEL_DEBUG
* - BLADERF_LOG_LEVEL_INFO
* - BLADERF_LOG_LEVEL_WARNING
* - BLADERF_LOG_LEVEL_ERROR
* - BLADERF_LOG_LEVEL_CRITICAL
* - BLADERF_LOG_LEVEL_SILENT
*/
bladerf_log_set_verbosity(BLADERF_LOG_LEVEL_INFO);
printf("BLADERF: Initializing openair0_device_t\n");
device->type = BLADERF_DEV;
device->trx_start_func = trx_brf_start;
device->trx_end_func = trx_brf_end;
device->trx_read_func = trx_brf_read;
device->trx_write_func = trx_brf_write;
device->trx_get_stats_func = trx_brf_get_stats;
device->trx_reset_stats_func = trx_brf_reset_stats;
device->trx_stop_func = trx_brf_stop;
device->trx_set_freq_func = trx_brf_set_freq;
device->trx_set_gains_func = trx_brf_set_gains;
device->trx_write_init = trx_brf_write_init;
device->openair0_cfg = openair0_cfg;
device->priv = (void *)brf;
// memcpy((void*)&device->openair0_cfg,(void*)&openair0_cfg[0],sizeof(openair0_config_t));
if ((status=bladerf_enable_module(brf->dev, BLADERF_MODULE_TX, false)) != 0) {
fprintf(stderr,"Failed to enable TX module: %s\n", bladerf_strerror(status));
abort();
}
if ((status=bladerf_enable_module(brf->dev, BLADERF_MODULE_RX, false)) != 0) {
fprintf(stderr,"Failed to enable RX module: %s\n", bladerf_strerror(status));
abort();
}
return 0;
return 0;
}