UHD: Initial RFNOC implementation

UHD: Fix RFNOC for multiple carriers
master
Xavier Arteaga 5 years ago committed by Xavier Arteaga
parent cfd3f51931
commit e4a794fdbd

@ -0,0 +1,98 @@
/*
* Copyright 2013-2020 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSLTE_RF_UHD_GENERIC_H
#define SRSLTE_RF_UHD_GENERIC_H
#include "rf_uhd_safe.h"
class rf_uhd_generic : public rf_uhd_safe_interface
{
public:
uhd_error usrp_make(const uhd::device_addr_t& dev_addr) override { return usrp_multi_make(dev_addr); }
uhd_error set_tx_subdev(const std::string& string) override
{
UHD_SAFE_C_SAVE_ERROR(this, usrp->set_tx_subdev_spec(string);)
}
uhd_error set_rx_subdev(const std::string& string) override
{
UHD_SAFE_C_SAVE_ERROR(this, usrp->set_rx_subdev_spec(string);)
}
uhd_error set_time_unknown_pps(const uhd::time_spec_t& timespec) override
{
UHD_SAFE_C_SAVE_ERROR(this, usrp->set_time_unknown_pps(timespec);)
}
uhd_error set_time_now(const uhd::time_spec_t& timespec) override
{
UHD_SAFE_C_SAVE_ERROR(this, usrp->set_time_now(timespec);)
}
uhd_error get_time_now(uhd::time_spec_t& timespec) override
{
UHD_SAFE_C_SAVE_ERROR(this, timespec = usrp->get_time_now();)
}
uhd_error set_sync_source(const std::string& source) override
{
#if UHD_VERSION < 3140099
UHD_SAFE_C_SAVE_ERROR(this, usrp->set_clock_source(source); usrp->set_time_source(source);)
#else
UHD_SAFE_C_SAVE_ERROR(this, usrp->set_sync_source(source, source);)
#endif
}
uhd_error set_master_clock_rate(double rate) override
{
UHD_SAFE_C_SAVE_ERROR(this, usrp->set_master_clock_rate(rate);)
}
uhd_error set_rx_rate(double rate) override { UHD_SAFE_C_SAVE_ERROR(this, usrp->set_rx_rate(rate);) }
uhd_error set_tx_rate(double rate) override { UHD_SAFE_C_SAVE_ERROR(this, usrp->set_tx_rate(rate);) }
uhd_error set_command_time(const uhd::time_spec_t& timespec) override
{
UHD_SAFE_C_SAVE_ERROR(this, usrp->set_command_time(timespec);)
}
uhd_error get_rx_stream(const uhd::stream_args_t& args, size_t& max_num_samps) override
{
UHD_SAFE_C_SAVE_ERROR(this, rx_stream = nullptr; rx_stream = usrp->get_rx_stream(args);
max_num_samps = rx_stream->get_max_num_samps();)
}
uhd_error get_tx_stream(const uhd::stream_args_t& args, size_t& max_num_samps) override
{
UHD_SAFE_C_SAVE_ERROR(this, tx_stream = nullptr; tx_stream = usrp->get_tx_stream(args);
max_num_samps = tx_stream->get_max_num_samps();)
}
uhd_error set_tx_gain(size_t ch, double gain) override { UHD_SAFE_C_SAVE_ERROR(this, usrp->set_tx_gain(gain, ch);) }
uhd_error set_rx_gain(size_t ch, double gain) override { UHD_SAFE_C_SAVE_ERROR(this, usrp->set_rx_gain(gain, ch);) }
uhd_error get_rx_gain(double& gain) override { UHD_SAFE_C_SAVE_ERROR(this, gain = usrp->get_rx_gain();) }
uhd_error get_tx_gain(double& gain) override { UHD_SAFE_C_SAVE_ERROR(this, gain = usrp->get_tx_gain();) }
uhd_error set_tx_freq(uint32_t ch, double target_freq, double& actual_freq) override
{
UHD_SAFE_C_SAVE_ERROR(this, uhd::tune_request_t tune_request(target_freq);
uhd::tune_result_t tune_result = usrp->set_tx_freq(tune_request, ch);
actual_freq = tune_result.target_rf_freq;)
}
uhd_error set_rx_freq(uint32_t ch, double target_freq, double& actual_freq) override
{
UHD_SAFE_C_SAVE_ERROR(this, uhd::tune_request_t tune_request(target_freq);
uhd::tune_result_t tune_result = usrp->set_rx_freq(tune_request, ch);
actual_freq = tune_result.target_rf_freq;)
}
};
#endif // SRSLTE_RF_UHD_GENERIC_H

@ -30,8 +30,9 @@
#include "rf_helper.h"
#include "srslte/srslte.h"
#include "rf_uhd_generic.h"
#include "rf_uhd_imp.h"
#include "rf_uhd_safe.h"
#include "rf_uhd_rfnoc.h"
#define HAVE_ASYNC_THREAD 1
@ -98,8 +99,8 @@ static const double RF_UHD_IMP_ASYNCH_MSG_TIMEOUT_S = 0.1;
static const uint32_t RF_UHD_IMP_MAX_RX_TRIALS = 100;
struct rf_uhd_handler_t {
std::string devname;
rf_uhd_safe uhd;
std::string devname;
rf_uhd_safe_interface* uhd = nullptr;
srslte_rf_info_t info;
size_t rx_nof_samples = 0;
@ -158,7 +159,7 @@ static cf_t zero_mem[64 * 1024] = {};
#define print_usrp_error(h) \
do { \
ERROR("USRP reported the following error: %s\n", h->uhd.last_error.c_str()); \
ERROR("USRP reported the following error: %s\n", h->uhd->last_error.c_str()); \
} while (false)
static void log_overflow(rf_uhd_handler_t* h)
@ -209,7 +210,7 @@ static void log_underflow(rf_uhd_handler_t* h)
static void log_rx_error(rf_uhd_handler_t* h)
{
if (h->uhd_error_handler) {
ERROR("USRP reported the following error: %s\n", h->uhd.last_error.c_str());
ERROR("USRP reported the following error: %s\n", h->uhd->last_error.c_str());
srslte_rf_error_t error;
bzero(&error, sizeof(srslte_rf_error_t));
@ -229,13 +230,13 @@ static void* async_thread(void* h)
bool valid = false;
// If the Tx stream is NULL wait for tx_cvar
if (not handler->uhd.is_tx_ready()) {
if (not handler->uhd->is_tx_ready()) {
handler->async_cvar.wait(lock);
}
if (handler->uhd.is_tx_ready()) {
if (handler->uhd->is_tx_ready()) {
lock.unlock();
if (handler->uhd.recv_async_msg(md, RF_UHD_IMP_ASYNCH_MSG_TIMEOUT_S, valid) != UHD_ERROR_NONE) {
if (handler->uhd->recv_async_msg(md, RF_UHD_IMP_ASYNCH_MSG_TIMEOUT_S, valid) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return nullptr;
}
@ -323,7 +324,7 @@ static int set_time_to_gps_time(rf_uhd_handler_t* handler)
const std::string sensor_name = "gps_time";
std::vector<std::string> sensors;
if (handler->uhd.get_mboard_sensor_names(sensors) != UHD_ERROR_NONE) {
if (handler->uhd->get_mboard_sensor_names(sensors) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
@ -349,7 +350,7 @@ static int set_time_to_gps_time(rf_uhd_handler_t* handler)
// Get actual sensor value
uhd::sensor_value_t sensor_value("w", "t", "f");
if (handler->uhd.get_sensor(sensor_name, sensor_value) != UHD_ERROR_NONE) {
if (handler->uhd->get_sensor(sensor_name, sensor_value) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
@ -357,7 +358,7 @@ static int set_time_to_gps_time(rf_uhd_handler_t* handler)
// Get time and set
double frac_secs = sensor_value.to_real();
printf("Setting USRP time to %fs\n", frac_secs);
if (handler->uhd.set_time_unknown_pps(uhd::time_spec_t(frac_secs)) != UHD_ERROR_NONE) {
if (handler->uhd->set_time_unknown_pps(uhd::time_spec_t(frac_secs)) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
@ -378,13 +379,13 @@ static int wait_sensor_locked(rf_uhd_handler_t* handler,
std::vector<std::string> sensors;
if (is_mboard) {
// motherboard sensor
if (handler->uhd.get_mboard_sensor_names(sensors) != UHD_ERROR_NONE) {
if (handler->uhd->get_mboard_sensor_names(sensors) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
} else {
// daughterboard sensor
if (handler->uhd.get_rx_sensor_names(sensors) != UHD_ERROR_NONE) {
if (handler->uhd->get_rx_sensor_names(sensors) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
@ -413,12 +414,12 @@ static int wait_sensor_locked(rf_uhd_handler_t* handler,
// Get actual sensor value
uhd::sensor_value_t sensor_value("", true, "True", "False");
if (is_mboard) {
if (handler->uhd.get_sensor(sensor_name, sensor_value) != UHD_ERROR_NONE) {
if (handler->uhd->get_sensor(sensor_name, sensor_value) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
} else {
if (handler->uhd.get_rx_sensor(sensor_name, sensor_value) != UHD_ERROR_NONE) {
if (handler->uhd->get_rx_sensor(sensor_name, sensor_value) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
@ -460,13 +461,13 @@ bool rf_uhd_rx_wait_lo_locked(void* h)
static inline int rf_uhd_start_rx_stream_unsafe(rf_uhd_handler_t* handler)
{
// Check if stream was not created or started
if (not handler->uhd.is_rx_ready() or handler->rx_stream_enabled) {
if (not handler->uhd->is_rx_ready() or handler->rx_stream_enabled) {
// Ignores command, the stream will start as soon as the Rx sampling rate is set
return SRSLTE_SUCCESS;
}
// Issue stream command
if (handler->uhd.start_rx_stream(RF_UHD_IMP_STREAM_DELAY_S) != UHD_ERROR_NONE) {
if (handler->uhd->start_rx_stream(RF_UHD_IMP_STREAM_DELAY_S) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
@ -487,13 +488,13 @@ int rf_uhd_start_rx_stream(void* h, bool now)
static inline int rf_uhd_stop_rx_stream_unsafe(rf_uhd_handler_t* handler)
{
// Check if stream was created or stream was not started
if (not handler->uhd.is_rx_ready() or not handler->rx_stream_enabled) {
if (not handler->uhd->is_rx_ready() or not handler->rx_stream_enabled) {
// Ignores command, the stream will start as soon as the Rx sampling rate is set
return SRSLTE_SUCCESS;
}
// Issue stream command
if (handler->uhd.stop_rx_stream() != UHD_ERROR_NONE) {
if (handler->uhd->stop_rx_stream() != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
@ -513,18 +514,25 @@ int rf_uhd_stop_rx_stream(void* h)
void rf_uhd_flush_buffer(void* h)
{
int n;
void* data[SRSLTE_MAX_CHANNELS] = {};
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
std::unique_lock<std::mutex> lock(handler->rx_mutex);
size_t rxd_samples = 0;
void* data[SRSLTE_MAX_CHANNELS] = {};
// Set all pointers to zero buffer
for (auto& i : data) {
i = zero_mem;
}
// Receive until times out
// Receive until time out
uhd::rx_metadata_t md;
do {
n = rf_uhd_recv_with_time_multi(h, data, 1024, false, nullptr, nullptr);
} while (n > 0);
if (handler->uhd->receive(data, handler->rx_nof_samples, md, 0.0, false, rxd_samples) != UHD_ERROR_NONE) {
log_rx_error(handler);
print_usrp_error(handler);
return;
}
} while (rxd_samples > 0 and md.error_code == uhd::rx_metadata_t::ERROR_CODE_NONE);
}
bool rf_uhd_has_rssi(void* h)
@ -666,8 +674,20 @@ int rf_uhd_open_multi(char* args, void** h, uint32_t nof_channels)
// Create UHD handler
printf("Opening USRP channels=%d, args: %s\n", nof_channels, device_addr.to_string().c_str());
// If RFNOC is accessible
#ifdef SRSLTE_RF_UHD_RFNOC_H
if (rf_uhd_rfnoc::is_required(device_addr)) {
handler->uhd = new rf_uhd_rfnoc;
}
#endif // SRSLTE_RF_UHD_RFNOC_H
// If UHD was not instanced, instance generic
if (handler->uhd == nullptr) {
handler->uhd = new rf_uhd_generic;
}
// Make USRP
if (handler->uhd.usrp_make(device_addr) != UHD_ERROR_NONE) {
if (handler->uhd->usrp_make(device_addr) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
@ -675,7 +695,7 @@ int rf_uhd_open_multi(char* args, void** h, uint32_t nof_channels)
// Set transmitter subdev spec if specified
if (not tx_subdev.empty()) {
printf("Setting tx_subdev_spec to '%s'\n", tx_subdev.c_str());
if (handler->uhd.set_tx_subdev(tx_subdev) != UHD_ERROR_NONE) {
if (handler->uhd->set_tx_subdev(tx_subdev) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
@ -684,7 +704,7 @@ int rf_uhd_open_multi(char* args, void** h, uint32_t nof_channels)
// Set receiver subdev spec if specified
if (not rx_subdev.empty()) {
printf("Setting rx_subdev_spec to '%s'\n", rx_subdev.c_str());
if (handler->uhd.set_rx_subdev(rx_subdev) != UHD_ERROR_NONE) {
if (handler->uhd->set_rx_subdev(rx_subdev) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
@ -706,7 +726,7 @@ int rf_uhd_open_multi(char* args, void** h, uint32_t nof_channels)
// If device name is not set, get it from motherboard
if (handler->devname.empty()) {
std::string mboard_name;
if (handler->uhd.get_mboard_name(mboard_name) != UHD_ERROR_NONE) {
if (handler->uhd->get_mboard_name(mboard_name) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
@ -731,7 +751,7 @@ int rf_uhd_open_multi(char* args, void** h, uint32_t nof_channels)
std::string sensor_name;
// Set sync source
if (handler->uhd.set_sync_source(clock_src) != UHD_ERROR_NONE) {
if (handler->uhd->set_sync_source(clock_src) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
@ -765,25 +785,25 @@ int rf_uhd_open_multi(char* args, void** h, uint32_t nof_channels)
handler->nof_rx_channels = nof_channels;
handler->nof_tx_channels = nof_channels;
if (handler->uhd.set_rx_rate(handler->rx_rate) != UHD_ERROR_NONE) {
if (handler->uhd->set_rx_rate(handler->rx_rate) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
if (handler->uhd.set_tx_rate(handler->tx_rate) != UHD_ERROR_NONE) {
if (handler->uhd->set_tx_rate(handler->tx_rate) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
if (nof_channels > 1 and clock_src != "gpsdo") {
handler->uhd.set_time_unknown_pps(uhd::time_spec_t());
handler->uhd->set_time_unknown_pps(uhd::time_spec_t());
}
if (handler->uhd.get_rx_stream(handler->stream_args, handler->rx_nof_samples) != UHD_ERROR_NONE) {
if (handler->uhd->get_rx_stream(handler->stream_args, handler->rx_nof_samples) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
if (handler->uhd.get_tx_stream(handler->stream_args, handler->tx_nof_samples) != UHD_ERROR_NONE) {
if (handler->uhd->get_tx_stream(handler->stream_args, handler->tx_nof_samples) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
@ -791,7 +811,7 @@ int rf_uhd_open_multi(char* args, void** h, uint32_t nof_channels)
// Populate RF device info
uhd::gain_range_t tx_gain_range;
uhd::gain_range_t rx_gain_range;
if (handler->uhd.get_gain_range(tx_gain_range, rx_gain_range) != UHD_ERROR_NONE) {
if (handler->uhd->get_gain_range(tx_gain_range, rx_gain_range) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
@ -842,7 +862,7 @@ static inline void rf_uhd_set_master_clock_rate_unsafe(rf_uhd_handler_t* handler
{
// Set master clock rate if it is allowed and change is required
if (handler->dynamic_master_rate && handler->current_master_clock != rate) {
if (handler->uhd.set_master_clock_rate(rate) != UHD_ERROR_NONE) {
if (handler->uhd->set_master_clock_rate(rate) != UHD_ERROR_NONE) {
print_usrp_error(handler);
}
handler->current_master_clock = rate;
@ -866,7 +886,7 @@ static inline int rf_uhd_imp_end_burst(rf_uhd_handler_t* handler)
md.end_of_burst = true;
// Actual base-band transmission
if (handler->uhd.send(buffs_ptr, 0, md, RF_UHD_IMP_TRX_TIMEOUT_S, txd_samples) != UHD_ERROR_NONE) {
if (handler->uhd->send(buffs_ptr, 0, md, RF_UHD_IMP_TRX_TIMEOUT_S, txd_samples) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
@ -883,7 +903,7 @@ double rf_uhd_set_rx_srate(void* h, double freq)
std::unique_lock<std::mutex> lock(handler->rx_mutex);
// Early return if the current rate matches and Rx stream has been created
if (freq == handler->rx_rate and handler->uhd.is_rx_ready()) {
if (freq == handler->rx_rate and handler->uhd->is_rx_ready()) {
return freq;
}
@ -899,22 +919,22 @@ double rf_uhd_set_rx_srate(void* h, double freq)
if (handler->nof_rx_channels > 1) {
uhd::time_spec_t timespec;
if (handler->uhd.get_time_now(timespec) != UHD_ERROR_NONE) {
if (handler->uhd->get_time_now(timespec) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
timespec += RF_UHD_IMP_TIMED_COMMAND_DELAY_S;
handler->uhd.set_command_time(timespec);
handler->uhd->set_command_time(timespec);
}
// Set RX rate
if (handler->uhd.set_rx_rate(freq) != UHD_ERROR_NONE) {
if (handler->uhd->set_rx_rate(freq) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
if (RH_UHD_IMP_PROHIBITED_STOP_START.count(handler->devname) == 0) {
if (handler->uhd.get_rx_stream(handler->stream_args, handler->rx_nof_samples) != UHD_ERROR_NONE) {
if (handler->uhd->get_rx_stream(handler->stream_args, handler->rx_nof_samples) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
@ -935,12 +955,12 @@ double rf_uhd_set_tx_srate(void* h, double freq)
#endif /* HAVE_ASYNC_THREAD */
// Early return if the current rate matches and Tx stream has been created
if (freq == handler->tx_rate and handler->uhd.is_tx_ready()) {
if (freq == handler->tx_rate and handler->uhd->is_tx_ready()) {
return freq;
}
// End burst
if (handler->uhd.is_tx_ready() and handler->tx_state != RF_UHD_IMP_TX_STATE_START_BURST) {
if (handler->uhd->is_tx_ready() and handler->tx_state != RF_UHD_IMP_TX_STATE_START_BURST) {
if (rf_uhd_imp_end_burst(handler) != SRSLTE_SUCCESS) {
return SRSLTE_ERROR;
}
@ -953,22 +973,22 @@ double rf_uhd_set_tx_srate(void* h, double freq)
if (handler->nof_tx_channels > 1) {
uhd::time_spec_t timespec;
if (handler->uhd.get_time_now(timespec) != UHD_ERROR_NONE) {
if (handler->uhd->get_time_now(timespec) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
timespec += RF_UHD_IMP_TIMED_COMMAND_DELAY_S;
handler->uhd.set_command_time(timespec);
handler->uhd->set_command_time(timespec);
}
// Set TX rate
if (handler->uhd.set_tx_rate(freq) != UHD_ERROR_NONE) {
if (handler->uhd->set_tx_rate(freq) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
if (RH_UHD_IMP_PROHIBITED_STOP_START.count(handler->devname) == 0) {
if (handler->uhd.get_tx_stream(handler->stream_args, handler->tx_nof_samples) != UHD_ERROR_NONE) {
if (handler->uhd->get_tx_stream(handler->stream_args, handler->tx_nof_samples) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
@ -999,7 +1019,7 @@ int rf_uhd_set_rx_gain(void* h, double gain)
int rf_uhd_set_rx_gain_ch(void* h, uint32_t ch, double gain)
{
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
if (handler->uhd.set_rx_gain(ch, gain) != UHD_ERROR_NONE) {
if (handler->uhd->set_rx_gain(ch, gain) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
@ -1021,7 +1041,7 @@ int rf_uhd_set_tx_gain(void* h, double gain)
int rf_uhd_set_tx_gain_ch(void* h, uint32_t ch, double gain)
{
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
if (handler->uhd.set_tx_gain(ch, gain) != UHD_ERROR_NONE) {
if (handler->uhd->set_tx_gain(ch, gain) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
@ -1033,7 +1053,7 @@ double rf_uhd_get_rx_gain(void* h)
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
double gain = 0.0;
if (handler->uhd.get_rx_gain(gain) != UHD_ERROR_NONE) {
if (handler->uhd->get_rx_gain(gain) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
@ -1046,7 +1066,7 @@ double rf_uhd_get_tx_gain(void* h)
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
double gain = 0.0;
if (handler->uhd.get_tx_gain(gain) != UHD_ERROR_NONE) {
if (handler->uhd->get_tx_gain(gain) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
@ -1070,13 +1090,13 @@ double rf_uhd_set_rx_freq(void* h, uint32_t ch, double freq)
{
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
if (ch < handler->nof_rx_channels) {
if (handler->uhd.set_rx_freq(ch, freq, freq) != UHD_ERROR_NONE) {
if (handler->uhd->set_rx_freq(ch, freq, freq) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
} else {
for (uint32_t i = 0; i < handler->nof_rx_channels; i++) {
if (handler->uhd.set_rx_freq(i, freq, freq) != UHD_ERROR_NONE) {
if (handler->uhd->set_rx_freq(i, freq, freq) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
@ -1090,13 +1110,13 @@ double rf_uhd_set_tx_freq(void* h, uint32_t ch, double freq)
{
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
if (ch < handler->nof_tx_channels) {
if (handler->uhd.set_tx_freq(ch, freq, freq) != UHD_ERROR_NONE) {
if (handler->uhd->set_tx_freq(ch, freq, freq) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
} else {
for (uint32_t i = 0; i < handler->nof_tx_channels; i++) {
if (handler->uhd.set_tx_freq(i, freq, freq) != UHD_ERROR_NONE) {
if (handler->uhd->set_tx_freq(i, freq, freq) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
@ -1109,7 +1129,7 @@ void rf_uhd_get_time(void* h, time_t* secs, double* frac_secs)
{
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
uhd::time_spec_t timespec;
if (handler->uhd.get_time_now(timespec) != UHD_ERROR_NONE) {
if (handler->uhd->get_time_now(timespec) != UHD_ERROR_NONE) {
print_usrp_error(handler);
}
if (secs != nullptr) {
@ -1129,7 +1149,7 @@ void rf_uhd_sync_pps(void* h)
rf_uhd_handler_t* handler = (rf_uhd_handler_t*)h;
uhd::time_spec_t timespec(0.0);
if (handler->uhd.set_time_unknown_pps(timespec) != UHD_ERROR_NONE) {
if (handler->uhd->set_time_unknown_pps(timespec) != UHD_ERROR_NONE) {
print_usrp_error(handler);
}
}
@ -1156,7 +1176,7 @@ int rf_uhd_recv_with_time_multi(void* h,
uhd::rx_metadata_t md;
// Check Rx stream has been created
if (not handler->uhd.is_rx_ready()) {
if (not handler->uhd->is_rx_ready()) {
// Ignores reception, the stream will start as soon as the Rx sampling rate is set
return SRSLTE_SUCCESS;
}
@ -1179,7 +1199,7 @@ int rf_uhd_recv_with_time_multi(void* h,
size_t num_samps_left = nsamples - rxd_samples_total;
size_t num_rx_samples = (num_samps_left > handler->rx_nof_samples) ? handler->rx_nof_samples : num_samps_left;
if (handler->uhd.receive(buffs_ptr, num_rx_samples, md, 1.0, false, rxd_samples) != UHD_ERROR_NONE) {
if (handler->uhd->receive(buffs_ptr, num_rx_samples, md, 1.0, false, rxd_samples) != UHD_ERROR_NONE) {
log_rx_error(handler);
print_usrp_error(handler);
return SRSLTE_ERROR;
@ -1269,7 +1289,7 @@ int rf_uhd_send_timed_multi(void* h,
int n = 0;
// Check Tx stream has been created
if (not handler->uhd.is_tx_ready()) {
if (not handler->uhd->is_tx_ready()) {
return SRSLTE_ERROR;
}
@ -1279,10 +1299,14 @@ int rf_uhd_send_timed_multi(void* h,
// Normal case, do nothing
break;
case RF_UHD_IMP_TX_STATE_END_OF_BURST:
// Send end of burst and ignore transmission
if (rf_uhd_imp_end_burst(handler) != SRSLTE_SUCCESS) {
return SRSLTE_ERROR;
}
handler->tx_state = RF_UHD_IMP_TX_STATE_START_BURST;
// Flush receiver
rf_uhd_flush_buffer(h);
return SRSLTE_ERROR;
case RF_UHD_IMP_TX_STATE_START_BURST:
// Set tart of burst to false if recovering from the Underflow
@ -1295,7 +1319,7 @@ int rf_uhd_send_timed_multi(void* h,
// If it the beginning of a burst, set timestamp
if (is_start_of_burst) {
// It gets the USRP time for transmissions without time
if (handler->uhd.get_time_now(md.time_spec) != UHD_ERROR_NONE) {
if (handler->uhd->get_time_now(md.time_spec) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}
@ -1339,7 +1363,7 @@ int rf_uhd_send_timed_multi(void* h,
buffs_ptr[i] = buff;
}
if (handler->uhd.send(buffs_ptr, tx_samples, md, RF_UHD_IMP_TRX_TIMEOUT_S, txd_samples) != UHD_ERROR_NONE) {
if (handler->uhd->send(buffs_ptr, tx_samples, md, RF_UHD_IMP_TRX_TIMEOUT_S, txd_samples) != UHD_ERROR_NONE) {
print_usrp_error(handler);
return SRSLTE_ERROR;
}

@ -0,0 +1,487 @@
/*
* Copyright 2013-2020 Software Radio Systems Limited
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <uhd/version.hpp>
// RF-NOC is only available for UHD 3.15 LTS
#if UHD_VERSION == 3150000
#ifndef SRSLTE_RF_UHD_RFNOC_H
#define SRSLTE_RF_UHD_RFNOC_H
#include <chrono>
#include <complex>
#include <csignal>
#include <fstream>
#include <iostream>
#include <thread>
#include <uhd/device3.hpp>
#include <uhd/error.h>
#include <uhd/rfnoc/block_ctrl.hpp>
#include <uhd/rfnoc/ddc_block_ctrl.hpp>
#include <uhd/rfnoc/dma_fifo_block_ctrl.hpp>
#include <uhd/rfnoc/duc_block_ctrl.hpp>
#include <uhd/rfnoc/graph.hpp>
#include <uhd/rfnoc/radio_ctrl.hpp>
#include <uhd/usrp/multi_usrp.hpp>
#include <uhd/utils/safe_main.hpp>
#include <uhd/utils/log.hpp>
#define Debug(message) UHD_LOG_DEBUG("UHD RF", message)
#include "rf_uhd_safe.h"
class rf_uhd_rfnoc : public rf_uhd_safe_interface
{
private:
uhd::device3::sptr device3;
uhd::rfnoc::graph::sptr tx_graph;
uhd::rfnoc::graph::sptr rx_graph;
// Constant parameters
const std::string RADIO_BLOCK_NAME = "Radio";
const std::string DDC_BLOCK_NAME = "DDC";
const std::string DUC_BLOCK_NAME = "DUC";
const std::string DMA_FIFO_BLOCK_NAME = "DmaFIFO";
const double SETUP_TIME_S = 1;
// Primary parameters
double master_clock_rate = 184.32e6;
double srate_hz = 0.0;
double bw_hz = 0.0;
size_t nof_radios = 1;
size_t nof_channels = 1;
double rx_gain_db = 10.0;
double tx_gain_db = 5.0;
std::vector<double> rx_freq_hz;
std::vector<double> tx_freq_hz;
std::string sync_source = "internal";
// Radio control
std::vector<uhd::rfnoc::radio_ctrl::sptr> radio_ctrl = {};
std::vector<uhd::rfnoc::block_id_t> radio_ctrl_id = {};
// DDC Control
std::vector<uhd::rfnoc::ddc_block_ctrl::sptr> ddc_ctrl = {};
std::vector<uhd::rfnoc::block_id_t> ddc_ctrl_id = {};
// DUC Control
std::vector<uhd::rfnoc::duc_block_ctrl::sptr> duc_ctrl = {};
std::vector<uhd::rfnoc::block_id_t> duc_ctrl_id = {};
// DMA FIFO Control
uhd::rfnoc::dma_fifo_block_ctrl::sptr dma_fifo_ctrl = {};
uhd::rfnoc::block_id_t dma_fifo_ctrl_id = {};
template <class T>
uhd_error parse_param(uhd::device_addr_t& args, const std::string& param, T& value)
{
UHD_SAFE_C_SAVE_ERROR(this,
// Check if parameter exists
if (not args.has_key(param)) {
last_error = "RF-NOC requires " + param + " parameter";
return UHD_ERROR_KEY;
}
// Parse parameter
value = args.cast(param, value);
// Remove parameter from list
args.pop(param);)
}
uhd_error parse_args(uhd::device_addr_t& args)
{
uhd_error err;
err = parse_param(args, "rfnoc_srate", srate_hz);
if (err != UHD_ERROR_NONE) {
return err;
}
parse_param(args, "rfnoc_nof_radios", nof_radios);
if (nof_radios == 0) {
last_error = "RF-NOC Number of radios cannot be zero";
return UHD_ERROR_KEY;
}
parse_param(args, "rfnoc_nof_channels", nof_channels);
if (nof_channels == 0) {
last_error = "RF-NOC Number of channels cannot be zero";
return UHD_ERROR_KEY;
}
// Optional parameters, ignore error return
parse_param(args, "rfnoc_tx_gain", tx_gain_db);
parse_param(args, "rfnoc_rx_gain", tx_gain_db);
// Parse Rx frequencies
rx_freq_hz.resize(nof_radios * nof_channels);
for (size_t radio_idx = 0; radio_idx < nof_radios; radio_idx++) {
for (size_t channel_idx = 0; channel_idx < nof_channels; channel_idx++) {
std::stringstream ss;
ss << "rfnoc_rx_" << radio_idx << "_" << channel_idx << "_freq";
err = parse_param(args, ss.str(), rx_freq_hz[radio_idx * nof_channels + channel_idx]);
if (err != UHD_ERROR_NONE) {
return err;
}
}
}
// Parse Rx frequencies
tx_freq_hz.resize(nof_radios * nof_channels);
for (size_t radio_idx = 0; radio_idx < nof_radios; radio_idx++) {
for (size_t channel_idx = 0; channel_idx < nof_channels; channel_idx++) {
std::stringstream ss;
ss << "rfnoc_tx_" << radio_idx << "_" << channel_idx << "_freq";
err = parse_param(args, ss.str(), tx_freq_hz[radio_idx * nof_channels + channel_idx]);
if (err != UHD_ERROR_NONE) {
return err;
}
}
}
// Secondary parameters
bw_hz = srate_hz * (1200.0 / 1536.0);
return UHD_ERROR_NONE;
}
uhd_error create_control_interfaces()
{
UHD_SAFE_C_SAVE_ERROR(
this,
// Create Radio control
radio_ctrl.resize(nof_radios);
radio_ctrl_id.resize(nof_radios);
for (size_t i = 0; i < nof_radios; i++) {
// Create handle for radio object
radio_ctrl_id[i] = uhd::rfnoc::block_id_t(0, RADIO_BLOCK_NAME, i);
// This next line will fail if the radio is not actually available
radio_ctrl[i] = device3->get_block_ctrl<uhd::rfnoc::radio_ctrl>(radio_ctrl_id[i]);
Debug("Using radio " << i);
}
// Create DDC control
ddc_ctrl.resize(nof_radios);
ddc_ctrl_id.resize(nof_radios);
for (size_t i = 0; i < nof_radios; i++) {
ddc_ctrl_id[i] = uhd::rfnoc::block_id_t(0, DDC_BLOCK_NAME, i);
ddc_ctrl[i] = device3->get_block_ctrl<uhd::rfnoc::ddc_block_ctrl>(ddc_ctrl_id[i]);
}
// Create DUC control
duc_ctrl.resize(nof_radios);
duc_ctrl_id.resize(nof_radios);
for (size_t i = 0; i < nof_radios; i++) {
duc_ctrl_id[i] = uhd::rfnoc::block_id_t(0, DUC_BLOCK_NAME, i);
duc_ctrl[i] = device3->get_block_ctrl<uhd::rfnoc::duc_block_ctrl>(duc_ctrl_id[i]);
}
// Create DMA FIFO control
dma_fifo_ctrl_id = uhd::rfnoc::block_id_t(0, DMA_FIFO_BLOCK_NAME);
dma_fifo_ctrl = device3->get_block_ctrl<uhd::rfnoc::dma_fifo_block_ctrl>(dma_fifo_ctrl_id);)
}
uhd_error configure()
{
UHD_SAFE_C_SAVE_ERROR(
this, std::vector<double> rx_center_freq_hz(nof_radios); std::vector<double> tx_center_freq_hz(nof_radios);
// Calculate center frequencies from averages
for (size_t radio_idx = 0; radio_idx < nof_radios; radio_idx++) {
double sum_tx = 0.0;
double sum_rx = 0.0;
for (size_t channel_idx = 0; channel_idx < nof_channels; channel_idx++) {
sum_tx += tx_freq_hz[radio_idx * nof_channels + channel_idx];
sum_rx += rx_freq_hz[radio_idx * nof_channels + channel_idx];
}
tx_center_freq_hz[radio_idx] = sum_tx / nof_channels;
rx_center_freq_hz[radio_idx] = sum_rx / nof_channels;
}
// Configure radios
for (size_t i = 0; i < nof_radios; ++i) {
Debug(boost::format("Setting radio %i...") % i);
// Lock mboard clocks
Debug("Setting sync source to " << sync_source) radio_ctrl[i]->set_clock_source(sync_source);
radio_ctrl[i]->set_time_source(sync_source);
// Set sample rate
Debug(boost::format("Setting TX/RX Rate: %f Msps...") % (master_clock_rate / 1e6));
radio_ctrl[i]->set_rate(master_clock_rate);
Debug(boost::format("Actual TX/RX Rate: %f Msps...") % (radio_ctrl[i]->get_rate() / 1e6));
// Set tx freq
Debug(boost::format("Setting TX Freq: %f MHz...") % (tx_center_freq_hz[i] / 1e6));
radio_ctrl[i]->set_tx_frequency(tx_center_freq_hz[i], 0);
tx_center_freq_hz[i] = radio_ctrl[i]->get_tx_frequency(0);
Debug(boost::format("Actual TX Freq: %f MHz...") % (tx_center_freq_hz[i] / 1e6));
// Set rx freq
Debug(boost::format("Setting RX Freq: %f MHz...") % (rx_center_freq_hz[i] / 1e6));
radio_ctrl[i]->set_rx_frequency(rx_center_freq_hz[i], 0);
rx_center_freq_hz[i] = radio_ctrl[i]->get_rx_frequency(0);
Debug(boost::format("Actual RX Freq: %f MHz...") % (rx_center_freq_hz[i] / 1e6));
// set the IF filter bandwidth
Debug(boost::format("Setting RX Bandwidth: %f MHz...") % (bw_hz / 1e6));
radio_ctrl[i]->set_rx_bandwidth(bw_hz, 0);
Debug(boost::format("Actual RX Bandwidth: %f MHz...") % (radio_ctrl[i]->get_rx_bandwidth(0) / 1e6));
// set the rf gain
Debug(boost::format("Setting RX Gain: %f dB...") % (rx_gain_db));
radio_ctrl[i]->set_rx_gain(rx_gain_db, 0);
Debug(boost::format("Actual RX Gain: %f dB...") % (radio_ctrl[i]->get_rx_gain(0)));
// set the antenna
radio_ctrl[i]->set_rx_antenna("TX/RX", 0);
}
// Sleep for some time
std::this_thread::sleep_for(std::chrono::milliseconds(int64_t(1000 * SETUP_TIME_S)));
// Setup DDCs and DUCs
for (size_t radio_idx = 0; radio_idx < nof_radios; radio_idx++) {
for (size_t channel_idx = 0; channel_idx < nof_channels; channel_idx++) {
uhd::device_addr_t ddc_args;
ddc_args.set("input_rate", std::to_string(master_clock_rate));
ddc_args.set(
"freq",
std::to_string(rx_freq_hz[nof_channels * radio_idx + channel_idx] - rx_center_freq_hz[radio_idx]));
ddc_args.set("fullscale", "1.0");
ddc_args.set("output_rate", std::to_string(srate_hz));
Debug("Configure " << ddc_ctrl_id[radio_idx] << ":" << channel_idx << "with args " << ddc_args.to_string());
ddc_ctrl[radio_idx]->set_args(ddc_args, channel_idx);
uhd::device_addr_t duc_args;
duc_args.set("input_rate", std::to_string(srate_hz));
duc_args.set(
"freq",
std::to_string(tx_freq_hz[nof_channels * radio_idx + channel_idx] - tx_center_freq_hz[radio_idx]));
duc_args.set("fullscale", "1.0");
duc_args.set("output_rate", std::to_string(master_clock_rate));
Debug("Configure " << duc_ctrl_id[radio_idx] << ":" << channel_idx << "with args " << duc_args.to_string());
duc_ctrl[radio_idx]->set_args(duc_args, channel_idx);
// Setup DMA FIFO
uhd::device_addr_t dma_fifo_args;
Debug("Configure " << dma_fifo_ctrl_id << ":" << nof_channels * radio_idx + channel_idx << " with args "
<< dma_fifo_args.to_string());
dma_fifo_ctrl->set_args(dma_fifo_args, nof_channels * radio_idx + channel_idx);
}
})
}
uhd_error connect()
{
UHD_SAFE_C_SAVE_ERROR(this, for (size_t radio_idx = 0; radio_idx < nof_radios; radio_idx++) {
// Radio -> DDC
Debug("Connecting " << radio_ctrl_id[radio_idx] << " -> " << ddc_ctrl_id[radio_idx]);
rx_graph->connect(radio_ctrl_id[radio_idx], 0, ddc_ctrl_id[radio_idx], 0);
// DUC -> Radio
Debug("Connecting " << duc_ctrl_id[radio_idx] << " -> " << radio_ctrl_id[radio_idx]);
tx_graph->connect(duc_ctrl_id[radio_idx], 0, radio_ctrl_id[radio_idx], 0);
// DMA FIFO -> DUC
for (size_t channel_idx = 0; channel_idx < nof_channels; channel_idx++) {
Debug("Connecting " << dma_fifo_ctrl_id << ":" << radio_idx * nof_channels + channel_idx << " -> "
<< radio_ctrl_id[radio_idx] << ":" << channel_idx);
tx_graph->connect(
dma_fifo_ctrl_id, radio_idx * nof_channels + channel_idx, duc_ctrl_id[radio_idx], channel_idx);
}
})
}
uhd_error get_streams()
{
UHD_SAFE_C_SAVE_ERROR(
this, uhd::stream_args_t tx_stream_args("fc32", "sc16"); uhd::stream_args_t rx_stream_args("fc32", "sc16");
tx_stream_args.channels.resize(nof_radios * nof_channels);
rx_stream_args.channels.resize(nof_radios * nof_channels);
// Populate stream arguments with RF-NOC blocks interfaces
size_t channel_count = 0;
for (size_t radio_idx = 0; radio_idx < nof_radios; radio_idx++) {
for (size_t channel_idx = 0; channel_idx < nof_channels; channel_idx++, channel_count++) {
std::string channel_str = std::to_string(channel_count);
tx_stream_args.args["block_id" + channel_str] = DMA_FIFO_BLOCK_NAME + "_0";
tx_stream_args.args["block_port" + channel_str] = std::to_string(radio_idx * nof_channels + channel_idx);
tx_stream_args.channels[channel_count] = channel_count;
rx_stream_args.args["block_id" + channel_str] = DDC_BLOCK_NAME + "_" + std::to_string(radio_idx);
rx_stream_args.args["block_port" + channel_str] = std::to_string(channel_idx);
rx_stream_args.channels[channel_count] = channel_count;
}
}
tx_stream = device3->get_tx_stream(tx_stream_args);
rx_stream = device3->get_rx_stream(rx_stream_args);)
}
uhd_error usrp_get_device3()
{
UHD_SAFE_C_SAVE_ERROR(this,
// Check if device is RF-NOC compatible
if (not usrp->is_device3()) {
last_error = "The selected device is not compatible with RF-NOC";
return UHD_ERROR_INVALID_DEVICE;
}
// Get device 3 shared pointer
device3 = usrp->get_device3();)
}
public:
static bool is_required(const uhd::device_addr_t& device_addr)
{
const std::vector<std::string> keys = device_addr.keys();
for (const std::string& k : keys) {
if (k.find("rfnoc") != std::string::npos) {
return true;
}
}
return false;
}
uhd_error usrp_make(const uhd::device_addr_t& _device_addr) override
{
// Copy device address
uhd::device_addr_t device_addr = _device_addr;
// Set log level to debug
uhd::log::set_console_level(uhd::log::severity_level::trace);
// Parse arguments, removes
uhd_error err = parse_args(device_addr);
if (err != UHD_ERROR_NONE) {
return err;
}
// Make USRP
err = usrp_multi_make(device_addr);
if (err != UHD_ERROR_NONE) {
return err;
}
err = usrp_get_device3();
if (err != UHD_ERROR_NONE) {
return err;
}
// Reset blocks after a stream
device3->clear();
// Create control interfaces
err = create_control_interfaces();
if (err != UHD_ERROR_NONE) {
return err;
}
return UHD_ERROR_NONE;
}
uhd_error set_tx_subdev(const std::string& string) override { return UHD_ERROR_NONE; }
uhd_error set_rx_subdev(const std::string& string) override { return UHD_ERROR_NONE; }
uhd_error set_time_unknown_pps(const uhd::time_spec_t& timespec) override { return UHD_ERROR_NONE; }
uhd_error set_time_now(const uhd::time_spec_t& timespec) override { return UHD_ERROR_NONE; }
uhd_error get_time_now(uhd::time_spec_t& timespec) override { return UHD_ERROR_NONE; }
uhd_error set_sync_source(const std::string& source) override
{
sync_source = source;
return UHD_ERROR_NONE;
}
uhd_error set_master_clock_rate(double rate) override { return UHD_ERROR_NONE; }
uhd_error set_rx_rate(double rate) override { return UHD_ERROR_NONE; }
uhd_error set_tx_rate(double rate) override { return UHD_ERROR_NONE; }
uhd_error set_command_time(const uhd::time_spec_t& timespec) override { return UHD_ERROR_NONE; }
uhd_error get_rx_stream(const uhd::stream_args_t& args, size_t& max_num_samps) override
{
uhd_error err;
// Get Tx and Rx Graph
tx_graph = device3->create_graph("tx_graph");
rx_graph = device3->create_graph("rx_graph");
// Configure components
err = configure();
if (err != UHD_ERROR_NONE) {
return err;
}
// Connect components
err = connect();
if (err != UHD_ERROR_NONE) {
return err;
}
// Get streams
err = get_streams();
if (err != UHD_ERROR_NONE) {
return err;
}
max_num_samps = rx_stream->get_max_num_samps();
return UHD_ERROR_NONE;
}
uhd_error get_tx_stream(const uhd::stream_args_t& args, size_t& max_num_samps) override
{
max_num_samps = tx_stream->get_max_num_samps();
return UHD_ERROR_NONE;
}
uhd_error set_tx_gain(size_t ch, double gain) override { return UHD_ERROR_NONE; }
uhd_error set_rx_gain(size_t ch, double gain) override { return UHD_ERROR_NONE; }
uhd_error get_rx_gain(double& gain) override { return UHD_ERROR_NONE; }
uhd_error get_tx_gain(double& gain) override { return UHD_ERROR_NONE; }
uhd_error set_tx_freq(uint32_t ch, double target_freq, double& actual_freq) override
{
if (ch < tx_freq_hz.size()) {
tx_freq_hz[ch] = target_freq;
actual_freq = tx_freq_hz[ch];
}
return UHD_ERROR_NONE;
}
uhd_error set_rx_freq(uint32_t ch, double target_freq, double& actual_freq) override
{
if (ch < rx_freq_hz.size()) {
rx_freq_hz[ch] = target_freq;
actual_freq = rx_freq_hz[ch];
}
return UHD_ERROR_NONE;
}
};
#endif // SRSLTE_RF_UHD_RFNOC_H
#endif // UHD_VERSION == 3150000

@ -27,9 +27,9 @@
uhd::wb_iface::sptr x300_make_ctrl_iface_enet(uhd::transport::udp_simple::sptr udp, bool enable_errors);
#endif /* ENABLE_UHD_X300_FW_RESET */
class rf_uhd_safe
class rf_uhd_safe_interface
{
private:
protected:
// List of errors that can happen in the USRP make that need to restart the device
const std::set<uhd_error> USRP_MAKE_RESET_ERR = {UHD_ERROR_IO};
@ -38,45 +38,7 @@ private:
uhd::rx_streamer::sptr rx_stream = nullptr;
uhd::tx_streamer::sptr tx_stream = nullptr;
uhd_error usrp_make_internal(const uhd::device_addr_t& dev_addr)
{
// Destroy any previous USRP instance
usrp.reset();
UHD_SAFE_C_SAVE_ERROR(this, usrp = uhd::usrp::multi_usrp::make(dev_addr);)
}
#ifdef ENABLE_UHD_X300_FW_RESET
uhd_error try_usrp_x300_reset(const uhd::device_addr_t& dev_addr)
{
UHD_SAFE_C_SAVE_ERROR(
this,
if (not dev_addr.has_key("addr")) { return UHD_ERROR_NONE; }
printf("Reseting X300 in address %s\n", dev_addr["addr"].c_str());
{ // Reset Scope
// Create UDP connection
uhd::transport::udp_simple::sptr udp_simple =
uhd::transport::udp_simple::make_connected(dev_addr["addr"], "49152");
// Create X300 control
uhd::wb_iface::sptr x300_ctrl = x300_make_ctrl_iface_enet(udp_simple, true);
// Reset FPGA firmware
x300_ctrl->poke32(0x100058, 1);
printf("Reset Done!\n");
}
return UHD_ERROR_NONE;)
}
#endif /* ENABLE_UHD_X300_FW_RESET */
public:
std::string last_error;
inline uhd_error usrp_make(const uhd::device_addr_t& dev_addr)
uhd_error usrp_multi_make(const uhd::device_addr_t& dev_addr)
{
uhd_error err = usrp_make_internal(dev_addr);
@ -93,21 +55,63 @@ public:
return err;
}
sleep(5);
// Try opening the device one more time
return usrp_make_internal(dev_addr);
#else /* ENABLE_UHD_X300_FW_RESET */
return err;
#endif /* ENABLE_UHD_X300_FW_RESET */
}
inline uhd_error set_tx_subdev(const std::string& string)
private:
uhd_error usrp_make_internal(const uhd::device_addr_t& dev_addr)
{
UHD_SAFE_C_SAVE_ERROR(this, usrp->set_tx_subdev_spec(string);)
// Destroy any previous USRP instance
usrp = nullptr;
UHD_SAFE_C_SAVE_ERROR(this, usrp = uhd::usrp::multi_usrp::make(dev_addr);)
}
inline uhd_error set_rx_subdev(const std::string& string)
#ifdef ENABLE_UHD_X300_FW_RESET
uhd_error try_usrp_x300_reset(const uhd::device_addr_t& dev_addr)
{
UHD_SAFE_C_SAVE_ERROR(this, usrp->set_rx_subdev_spec(string);)
UHD_SAFE_C_SAVE_ERROR(this,
// Destroy any previous USRP instance
usrp = nullptr;
// It is not possible to reset device if IP address is not provided
if (not dev_addr.has_key("addr")) { return UHD_ERROR_NONE; }
printf("Reseting X300 in address %s\n", dev_addr["addr"].c_str());
{ // Reset Scope
// Create UDP connection
uhd::transport::udp_simple::sptr udp_simple =
uhd::transport::udp_simple::make_connected(dev_addr["addr"], "49152");
// Create X300 control
uhd::wb_iface::sptr x300_ctrl = x300_make_ctrl_iface_enet(udp_simple, true);
// Reset FPGA firmware
x300_ctrl->poke32(0x100058, 1);
printf("Reset Done!\n");
x300_ctrl = nullptr;
udp_simple = nullptr;
}
return UHD_ERROR_NONE;)
}
inline uhd_error get_mboard_name(std::string& mboard_name)
#endif /* ENABLE_UHD_X300_FW_RESET */
public:
std::string last_error;
virtual uhd_error usrp_make(const uhd::device_addr_t& dev_addr) = 0;
virtual uhd_error set_tx_subdev(const std::string& string) = 0;
virtual uhd_error set_rx_subdev(const std::string& string) = 0;
inline uhd_error get_mboard_name(std::string& mboard_name)
{
UHD_SAFE_C_SAVE_ERROR(this, mboard_name = usrp->get_mboard_name();)
}
@ -127,19 +131,10 @@ public:
{
UHD_SAFE_C_SAVE_ERROR(this, sensor_value = usrp->get_rx_sensor(sensor_name);)
}
inline uhd_error set_time_unknown_pps(const uhd::time_spec_t& timespec)
{
UHD_SAFE_C_SAVE_ERROR(this, usrp->set_time_unknown_pps(timespec);)
}
inline uhd_error set_time_now(const uhd::time_spec_t& timespec)
{
UHD_SAFE_C_SAVE_ERROR(this, usrp->set_time_now(timespec);)
}
inline uhd_error get_time_now(uhd::time_spec_t& timespec)
{
UHD_SAFE_C_SAVE_ERROR(this, timespec = usrp->get_time_now();)
}
inline uhd_error start_rx_stream(double delay)
virtual uhd_error set_time_unknown_pps(const uhd::time_spec_t& timespec) = 0;
virtual uhd_error set_time_now(const uhd::time_spec_t& timespec) = 0;
virtual uhd_error get_time_now(uhd::time_spec_t& timespec) = 0;
inline uhd_error start_rx_stream(double delay)
{
UHD_SAFE_C_SAVE_ERROR(this, uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_START_CONTINUOUS);
stream_cmd.time_spec = usrp->get_time_now();
@ -153,62 +148,31 @@ public:
UHD_SAFE_C_SAVE_ERROR(this, uhd::stream_cmd_t stream_cmd(uhd::stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS);
rx_stream->issue_stream_cmd(stream_cmd);)
}
inline uhd_error set_sync_source(const std::string& source)
{
#if UHD_VERSION < 3140099
UHD_SAFE_C_SAVE_ERROR(this, usrp->set_clock_source(source); usrp->set_time_source(source);)
#else
UHD_SAFE_C_SAVE_ERROR(this, usrp->set_sync_source(source, source);)
#endif
}
inline uhd_error get_gain_range(uhd::gain_range_t& tx_gain_range, uhd::gain_range_t& rx_gain_range)
virtual uhd_error set_sync_source(const std::string& source) = 0;
uhd_error get_gain_range(uhd::gain_range_t& tx_gain_range, uhd::gain_range_t& rx_gain_range)
{
UHD_SAFE_C_SAVE_ERROR(this, tx_gain_range = usrp->get_tx_gain_range(); rx_gain_range = usrp->get_rx_gain_range();)
}
inline uhd_error set_master_clock_rate(double rate)
{
UHD_SAFE_C_SAVE_ERROR(this, usrp->set_master_clock_rate(rate);)
}
inline uhd_error set_rx_rate(double rate) { UHD_SAFE_C_SAVE_ERROR(this, usrp->set_rx_rate(rate);) }
inline uhd_error set_tx_rate(double rate) { UHD_SAFE_C_SAVE_ERROR(this, usrp->set_tx_rate(rate);) }
inline uhd_error set_command_time(const uhd::time_spec_t& timespec)
{
UHD_SAFE_C_SAVE_ERROR(this, usrp->set_command_time(timespec);)
}
inline uhd_error destroy_rx_stream() { UHD_SAFE_C_SAVE_ERROR(this, rx_stream = nullptr;) }
inline uhd_error get_rx_stream(const uhd::stream_args_t& args, size_t& max_num_samps)
{
UHD_SAFE_C_SAVE_ERROR(this, rx_stream = nullptr; rx_stream = usrp->get_rx_stream(args);
max_num_samps = rx_stream->get_max_num_samps();)
}
inline uhd_error destroy_tx_stream() { UHD_SAFE_C_SAVE_ERROR(this, rx_stream = nullptr;) }
inline uhd_error get_tx_stream(const uhd::stream_args_t& args, size_t& max_num_samps)
{
UHD_SAFE_C_SAVE_ERROR(this, tx_stream = nullptr; tx_stream = usrp->get_tx_stream(args);
max_num_samps = tx_stream->get_max_num_samps();)
}
inline uhd_error set_tx_gain(size_t ch, double gain) { UHD_SAFE_C_SAVE_ERROR(this, usrp->set_tx_gain(gain, ch);) }
inline uhd_error set_rx_gain(size_t ch, double gain) { UHD_SAFE_C_SAVE_ERROR(this, usrp->set_rx_gain(gain, ch);) }
inline uhd_error get_rx_gain(double& gain) { UHD_SAFE_C_SAVE_ERROR(this, gain = usrp->get_rx_gain();) }
inline uhd_error get_tx_gain(double& gain) { UHD_SAFE_C_SAVE_ERROR(this, gain = usrp->get_tx_gain();) }
inline uhd_error set_tx_freq(uint32_t ch, double target_freq, double& actual_freq)
{
UHD_SAFE_C_SAVE_ERROR(this, uhd::tune_request_t tune_request(target_freq);
uhd::tune_result_t tune_result = usrp->set_tx_freq(tune_request, ch);
actual_freq = tune_result.target_rf_freq;)
}
inline uhd_error set_rx_freq(uint32_t ch, double target_freq, double& actual_freq)
{
UHD_SAFE_C_SAVE_ERROR(this, uhd::tune_request_t tune_request(target_freq);
uhd::tune_result_t tune_result = usrp->set_rx_freq(tune_request, ch);
actual_freq = tune_result.target_rf_freq;)
}
inline uhd_error receive(void** buffs,
const size_t nsamps_per_buff,
uhd::rx_metadata_t& metadata,
const double timeout,
const bool one_packet,
size_t& nof_rxd_samples)
virtual uhd_error set_master_clock_rate(double rate) = 0;
virtual uhd_error set_rx_rate(double rate) = 0;
virtual uhd_error set_tx_rate(double rate) = 0;
virtual uhd_error set_command_time(const uhd::time_spec_t& timespec) = 0;
virtual uhd_error get_rx_stream(const uhd::stream_args_t& args, size_t& max_num_samps) = 0;
inline uhd_error destroy_rx_stream() { UHD_SAFE_C_SAVE_ERROR(this, rx_stream = nullptr;) }
virtual uhd_error get_tx_stream(const uhd::stream_args_t& args, size_t& max_num_samps) = 0;
inline uhd_error destroy_tx_stream() { UHD_SAFE_C_SAVE_ERROR(this, rx_stream = nullptr;) }
virtual uhd_error set_tx_gain(size_t ch, double gain) = 0;
virtual uhd_error set_rx_gain(size_t ch, double gain) = 0;
virtual uhd_error get_rx_gain(double& gain) = 0;
virtual uhd_error get_tx_gain(double& gain) = 0;
virtual uhd_error set_tx_freq(uint32_t ch, double target_freq, double& actual_freq) = 0;
virtual uhd_error set_rx_freq(uint32_t ch, double target_freq, double& actual_freq) = 0;
inline uhd_error receive(void** buffs,
const size_t nsamps_per_buff,
uhd::rx_metadata_t& metadata,
const double timeout,
const bool one_packet,
size_t& nof_rxd_samples)
{
UHD_SAFE_C_SAVE_ERROR(this, uhd::rx_streamer::buffs_type buffs_cpp(buffs, rx_stream->get_num_channels());
nof_rxd_samples = rx_stream->recv(buffs_cpp, nsamps_per_buff, metadata, timeout, one_packet);)

Loading…
Cancel
Save