diff --git a/cmake/modules/FindUHD.cmake b/cmake/modules/FindUHD.cmake index 438118f46..44dcfe7fd 100644 --- a/cmake/modules/FindUHD.cmake +++ b/cmake/modules/FindUHD.cmake @@ -31,14 +31,15 @@ MARK_AS_ADVANCED(UHD_LIBRARIES UHD_INCLUDE_DIRS) include(CheckCXXSourceCompiles) IF(UHD_FOUND) - # Checks whether the UHD driver supports X300 reset from srsLTE. This functionality requires changing the function - # `x300_make_ctrl_iface_enet` visibility in the file `uhd/host/lib/usrp/x300_fw_ctrl.cpp`. This can be accomplished - # adding the following line: - # `UHD_API wb_iface::sptr x300_make_ctrl_iface_enet(uhd::transport::udp_simple::sptr udp, bool enable_errors);` set(_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) set(_CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) set(CMAKE_REQUIRED_FLAGS ${CMAKE_CXX_FLAGS}) set(CMAKE_REQUIRED_LIBRARIES uhd boost_program_options boost_system) + + # Checks whether the UHD driver supports X300 reset from srsLTE. This functionality requires changing the function + # `x300_make_ctrl_iface_enet` visibility in the file `uhd/host/lib/usrp/x300_fw_ctrl.cpp`. This can be accomplished + # adding the following line: + # `UHD_API wb_iface::sptr x300_make_ctrl_iface_enet(uhd::transport::udp_simple::sptr udp, bool enable_errors);` check_cxx_source_compiles("#include #include #include @@ -59,6 +60,26 @@ IF(UHD_FOUND) return 0; }" UHD_ENABLE_X300_FW_RESET) + # Checks whether the UHD driver supports X300 custom RF-NOC devices + check_cxx_source_compiles("#include + #include + #include + + static uhd::device3::sptr device3; + static uhd::rfnoc::ddc_ch2_block_ctrl::sptr ddc_ctrl; + + uhd_error try_device3_ddc_ch2_ctrl() + { + ddc_ctrl = device3->get_block_ctrl(uhd::rfnoc::block_id_t(\"DDCch2_0\")); + return UHD_ERROR_NONE; + } + + int main(int argc, char** argv) + { + try_device3_ddc_ch2_ctrl(); + return 0; + }" UHD_ENABLE_CUSTOM_RFNOC) + set(CMAKE_REQUIRED_FLAGS ${_CMAKE_REQUIRED_FLAGS}) set(CMAKE_REQUIRED_LIBRARIES ${_CMAKE_REQUIRED_LIBRARIES}) ENDIF(UHD_FOUND) diff --git a/lib/src/phy/rf/CMakeLists.txt b/lib/src/phy/rf/CMakeLists.txt index 5f075dc35..c3decabd5 100644 --- a/lib/src/phy/rf/CMakeLists.txt +++ b/lib/src/phy/rf/CMakeLists.txt @@ -35,6 +35,9 @@ if(RF_FOUND) if (UHD_ENABLE_X300_FW_RESET) add_definitions(-DENABLE_UHD_X300_FW_RESET) endif(UHD_ENABLE_X300_FW_RESET) + if (UHD_ENABLE_CUSTOM_RFNOC) + add_definitions(-DUHD_ENABLE_CUSTOM_RFNOC) + endif(UHD_ENABLE_CUSTOM_RFNOC) endif (UHD_FOUND) if (BLADERF_FOUND) diff --git a/lib/src/phy/rf/rf_uhd_generic.h b/lib/src/phy/rf/rf_uhd_generic.h index 41d1ab83f..32c019b52 100644 --- a/lib/src/phy/rf/rf_uhd_generic.h +++ b/lib/src/phy/rf/rf_uhd_generic.h @@ -26,6 +26,17 @@ class rf_uhd_generic : public rf_uhd_safe_interface { +private: + uhd::usrp::multi_usrp::sptr usrp = nullptr; + + uhd_error usrp_make_internal(const uhd::device_addr_t& dev_addr) override + { + // Destroy any previous USRP instance + usrp = nullptr; + + UHD_SAFE_C_SAVE_ERROR(this, usrp = uhd::usrp::multi_usrp::make(dev_addr);) + } + public: uhd_error usrp_make(const uhd::device_addr_t& dev_addr) override { return usrp_multi_make(dev_addr); } @@ -37,13 +48,29 @@ public: { 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_error get_mboard_name(std::string& mboard_name) override { - UHD_SAFE_C_SAVE_ERROR(this, usrp->set_time_unknown_pps(timespec);) + UHD_SAFE_C_SAVE_ERROR(this, mboard_name = usrp->get_mboard_name();) } - uhd_error set_time_now(const uhd::time_spec_t& timespec) override + uhd_error get_mboard_sensor_names(std::vector& sensors) override { - UHD_SAFE_C_SAVE_ERROR(this, usrp->set_time_now(timespec);) + UHD_SAFE_C_SAVE_ERROR(this, sensors = usrp->get_mboard_sensor_names();) + } + uhd_error get_rx_sensor_names(std::vector& sensors) override + { + UHD_SAFE_C_SAVE_ERROR(this, sensors = usrp->get_rx_sensor_names();) + } + uhd_error get_sensor(const std::string& sensor_name, uhd::sensor_value_t& sensor_value) override + { + UHD_SAFE_C_SAVE_ERROR(this, sensor_value = usrp->get_mboard_sensor(sensor_name);) + } + uhd_error get_rx_sensor(const std::string& sensor_name, uhd::sensor_value_t& sensor_value) override + { + UHD_SAFE_C_SAVE_ERROR(this, sensor_value = usrp->get_rx_sensor(sensor_name);) + } + 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 get_time_now(uhd::time_spec_t& timespec) override { @@ -57,6 +84,10 @@ public: UHD_SAFE_C_SAVE_ERROR(this, usrp->set_sync_source(source, source);) #endif } + uhd_error get_gain_range(uhd::gain_range_t& tx_gain_range, uhd::gain_range_t& rx_gain_range) override + { + UHD_SAFE_C_SAVE_ERROR(this, tx_gain_range = usrp->get_tx_gain_range(); rx_gain_range = usrp->get_rx_gain_range();) + } uhd_error set_master_clock_rate(double rate) override { UHD_SAFE_C_SAVE_ERROR(this, usrp->set_master_clock_rate(rate);) diff --git a/lib/src/phy/rf/rf_uhd_imp.cc b/lib/src/phy/rf/rf_uhd_imp.cc index 4b8c8f02b..13a375483 100644 --- a/lib/src/phy/rf/rf_uhd_imp.cc +++ b/lib/src/phy/rf/rf_uhd_imp.cc @@ -99,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_interface* uhd = nullptr; + std::string devname; + std::shared_ptr uhd = nullptr; srslte_rf_info_t info; size_t rx_nof_samples = 0; @@ -677,13 +677,13 @@ int rf_uhd_open_multi(char* args, void** h, uint32_t nof_channels) // If RFNOC is accessible #ifdef SRSLTE_RF_UHD_RFNOC_H if (rf_uhd_rfnoc::is_required(device_addr)) { - handler->uhd = new rf_uhd_rfnoc; + handler->uhd = std::make_shared(); } #endif // SRSLTE_RF_UHD_RFNOC_H // If UHD was not instanced, instance generic if (handler->uhd == nullptr) { - handler->uhd = new rf_uhd_generic; + handler->uhd = std::make_shared(); } // Make USRP diff --git a/lib/src/phy/rf/rf_uhd_rfnoc.h b/lib/src/phy/rf/rf_uhd_rfnoc.h index d0b8e05bf..a53ad0df6 100644 --- a/lib/src/phy/rf/rf_uhd_rfnoc.h +++ b/lib/src/phy/rf/rf_uhd_rfnoc.h @@ -22,7 +22,7 @@ #include // RF-NOC is only available for UHD 3.15 LTS -#if UHD_VERSION == 3150000 +#if UHD_VERSION >= 3150000 && UHD_VERSION < 3160000 #ifndef SRSLTE_RF_UHD_RFNOC_H #define SRSLTE_RF_UHD_RFNOC_H @@ -37,16 +37,20 @@ #include #include #include -#include #include -#include #include #include #include #include -#include -#define Debug(message) UHD_LOG_DEBUG("UHD RF", message) +// Load custom RFNOC blocks if available +#ifdef UHD_ENABLE_CUSTOM_RFNOC +#include +#include +#else // UHD_ENABLE_CUSTOM_RFNOC +#include +#include +#endif // UHD_ENABLE_CUSTOM_RFNOC #include "rf_uhd_safe.h" @@ -58,11 +62,23 @@ private: 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; + const std::string RADIO_BLOCK_NAME = "Radio"; +#ifdef UHD_ENABLE_CUSTOM_RFNOC + const std::string DDC_BLOCK_NAME = "DDCch2"; + const std::string DUC_BLOCK_NAME = "DUCch2"; + typedef uhd::rfnoc::ddc_ch2_block_ctrl ddc_ctrl_t; + typedef uhd::rfnoc::duc_ch2_block_ctrl duc_ctrl_t; +#else // UHD_ENABLE_CUSTOM_RFNOC + const std::string DDC_BLOCK_NAME = "DDC"; + const std::string DUC_BLOCK_NAME = "DUC"; + typedef uhd::rfnoc::ddc_block_ctrl::sptr ddc_ctrl_t; + typedef uhd::rfnoc::duc_block_ctrl::sptr duc_ctrl_t; +#endif // UHD_ENABLE_CUSTOM_RFNOC + + const std::string DMA_FIFO_BLOCK_NAME = "DmaFIFO"; + const double SETUP_TIME_S = 1.0; + const uhd::fs_path TREE_MBOARD_SENSORS = "/mboards/0/sensors"; + const uhd::fs_path TREE_RX_SENSORS = "/mboards/0/dboards/A/rx_frontends/0/sensors"; // Primary parameters double master_clock_rate = 184.32e6; @@ -74,23 +90,33 @@ private: double tx_gain_db = 5.0; std::vector rx_freq_hz; std::vector tx_freq_hz; - std::string sync_source = "internal"; + std::string sync_source = "internal"; + size_t nof_samples_per_packet = 0; + size_t dma_fifo_depth = 8192UL * 4096UL; // Radio control - std::vector radio_ctrl = {}; - std::vector radio_ctrl_id = {}; + std::vector radio_ctrl = {}; + std::vector radio_id = {}; // DDC Control - std::vector ddc_ctrl = {}; - std::vector ddc_ctrl_id = {}; + std::vector ddc_ctrl = {}; + std::vector ddc_id = {}; // DUC Control - std::vector duc_ctrl = {}; - std::vector duc_ctrl_id = {}; + std::vector duc_ctrl = {}; + std::vector duc_id = {}; // DMA FIFO Control - uhd::rfnoc::dma_fifo_block_ctrl::sptr dma_fifo_ctrl = {}; - uhd::rfnoc::block_id_t dma_fifo_ctrl_id = {}; + uhd::rfnoc::dma_fifo_block_ctrl::sptr dma_ctrl = {}; + uhd::rfnoc::block_id_t dma_id = {}; + + uhd_error usrp_make_internal(const uhd::device_addr_t& dev_addr) override + { + // Destroy any previous USRP instance + device3 = nullptr; + + UHD_SAFE_C_SAVE_ERROR(this, device3 = uhd::device3::make(dev_addr);) + } template uhd_error parse_param(uhd::device_addr_t& args, const std::string& param, T& value) @@ -172,34 +198,34 @@ private: this, // Create Radio control radio_ctrl.resize(nof_radios); - radio_ctrl_id.resize(nof_radios); + radio_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); + radio_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(radio_ctrl_id[i]); + radio_ctrl[i] = device3->get_block_ctrl(radio_id[i]); Debug("Using radio " << i); } // Create DDC control ddc_ctrl.resize(nof_radios); - ddc_ctrl_id.resize(nof_radios); + ddc_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(ddc_ctrl_id[i]); + ddc_id[i] = uhd::rfnoc::block_id_t(0, DDC_BLOCK_NAME, i); + ddc_ctrl[i] = device3->get_block_ctrl(ddc_id[i]); } // Create DUC control duc_ctrl.resize(nof_radios); - duc_ctrl_id.resize(nof_radios); + duc_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(duc_ctrl_id[i]); + duc_id[i] = uhd::rfnoc::block_id_t(0, DUC_BLOCK_NAME, i); + duc_ctrl[i] = device3->get_block_ctrl(duc_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(dma_fifo_ctrl_id);) + dma_id = uhd::rfnoc::block_id_t(0, DMA_FIFO_BLOCK_NAME); + dma_ctrl = device3->get_block_ctrl(dma_id);) } uhd_error configure() @@ -223,37 +249,37 @@ private: // Configure radios for (size_t i = 0; i < nof_radios; ++i) { - Debug(boost::format("Setting radio %i...") % i); + Debug("Setting radio " << 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)); + Debug("Setting TX/RX Rate: " << master_clock_rate / 1e6 << " Msps..."); radio_ctrl[i]->set_rate(master_clock_rate); - Debug(boost::format("Actual TX/RX Rate: %f Msps...") % (radio_ctrl[i]->get_rate() / 1e6)); + Debug("Actual TX/RX Rate:" << radio_ctrl[i]->get_rate() / 1e6 << " Msps..."); // Set tx freq - Debug(boost::format("Setting TX Freq: %f MHz...") % (tx_center_freq_hz[i] / 1e6)); + Debug("Setting TX Freq: " << tx_center_freq_hz[i] / 1e6 << " MHz..."); 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)); + Debug("Actual TX Freq: " << tx_center_freq_hz[i] / 1e6 << " MHz..."); // Set rx freq - Debug(boost::format("Setting RX Freq: %f MHz...") % (rx_center_freq_hz[i] / 1e6)); + Debug("Setting RX Freq: " << rx_center_freq_hz[i] / 1e6 << " MHz..."); 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)); + Debug("Actual RX Freq: " << rx_center_freq_hz[i] / 1e6 << " MHz..."); // set the IF filter bandwidth - Debug(boost::format("Setting RX Bandwidth: %f MHz...") % (bw_hz / 1e6)); + Debug("Setting RX Bandwidth: " << bw_hz / 1e6 << " MHz..."); 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)); + Debug("Actual RX Bandwidth: " << radio_ctrl[i]->get_rx_bandwidth(0) / 1e6 << " MHz..."); // set the rf gain - Debug(boost::format("Setting RX Gain: %f dB...") % (rx_gain_db)); + Debug("Setting RX Gain: " << rx_gain_db << " 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))); + Debug("Actual RX Gain: " << radio_ctrl[i]->get_rx_gain(0) << " dB..."); // set the antenna radio_ctrl[i]->set_rx_antenna("TX/RX", 0); @@ -265,36 +291,43 @@ private: // 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); + size_t rf_channel_idx = nof_channels * radio_idx + channel_idx; + + { // Setup DDC + uhd::device_addr_t ddc_args; + ddc_args.set("output_rate", std::to_string(srate_hz)); + ddc_args.set("input_rate", std::to_string(master_clock_rate)); + ddc_args.set("freq", std::to_string(rx_freq_hz[rf_channel_idx] - rx_center_freq_hz[radio_idx])); + ddc_args.set("fullscale", "1.0"); + + Debug("Configure " << ddc_id[radio_idx] << ":" << channel_idx << " with args " << ddc_args.to_string()); + + ddc_ctrl[radio_idx]->set_args(ddc_args, channel_idx); + } + + { // Setup DUC + uhd::device_addr_t duc_args; + duc_args.set("output_rate", std::to_string(master_clock_rate)); + duc_args.set("input_rate", std::to_string(srate_hz)); + duc_args.set("freq", std::to_string(tx_freq_hz[rf_channel_idx] - tx_center_freq_hz[radio_idx])); + duc_args.set("fullscale", "1.0"); + + Debug("Configure " << duc_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; + dma_fifo_args.set("base_addr", std::to_string(dma_fifo_depth * rf_channel_idx)); + dma_fifo_args.set("depth", std::to_string(dma_fifo_depth)); + + Debug("Configure " << dma_id << ":" << rf_channel_idx << " with args " << dma_fifo_args.to_string()); + + dma_ctrl->set_args(dma_fifo_args, rf_channel_idx); + } } + Debug("Configuration done!") }) } @@ -302,19 +335,18 @@ private: { 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); + Debug("Connecting " << radio_id[radio_idx] << ":0 -> " << ddc_id[radio_idx] << ":0"); + rx_graph->connect(radio_id[radio_idx], 0, ddc_id[radio_idx], 0, nof_samples_per_packet); // 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); + Debug("Connecting " << duc_id[radio_idx] << ":0 -> " << radio_id[radio_idx] << ":0"); + tx_graph->connect(duc_id[radio_idx], 0, radio_id[radio_idx], 0, nof_samples_per_packet); // 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); + size_t dma_port = radio_idx * nof_channels + channel_idx; + Debug("Connecting " << dma_id << ":" << dma_port << " -> " << duc_id[radio_idx] << ":" << channel_idx); + tx_graph->connect(dma_id, dma_port, duc_id[radio_idx], channel_idx, nof_samples_per_packet); } }) } @@ -343,21 +375,11 @@ private: } } + Debug("Getting Tx Stream with arguments " << tx_stream_args.args.to_pp_string()); 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();) + Debug("Getting Rx Stream with arguments " << rx_stream_args.args.to_pp_string()); + rx_stream = device3->get_rx_stream(rx_stream_args);) } public: @@ -394,11 +416,6 @@ public: return err; } - err = usrp_get_device3(); - if (err != UHD_ERROR_NONE) { - return err; - } - // Reset blocks after a stream device3->clear(); @@ -413,14 +430,54 @@ public: 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 get_mboard_name(std::string& mboard_name) override + { + mboard_name = "X300"; + return UHD_ERROR_NONE; + }; + uhd_error get_mboard_sensor_names(std::vector& sensors) override + { + UHD_SAFE_C_SAVE_ERROR(this, if (device3->get_tree()->exists(TREE_MBOARD_SENSORS)) { + sensors = device3->get_tree()->list(TREE_MBOARD_SENSORS); + }) + } + uhd_error get_rx_sensor_names(std::vector& sensors) override + { + UHD_SAFE_C_SAVE_ERROR(this, if (device3->get_tree()->exists(TREE_RX_SENSORS)) { + sensors = device3->get_tree()->list(TREE_RX_SENSORS); + }) + } + uhd_error get_sensor(const std::string& sensor_name, uhd::sensor_value_t& sensor_value) override + { + UHD_SAFE_C_SAVE_ERROR( + this, sensor_value = device3->get_tree()->access(TREE_MBOARD_SENSORS / sensor_name).get();) + } + uhd_error get_rx_sensor(const std::string& sensor_name, uhd::sensor_value_t& sensor_value) override + { + UHD_SAFE_C_SAVE_ERROR( + this, sensor_value = device3->get_tree()->access(TREE_RX_SENSORS / sensor_name).get();) + } + uhd_error set_time_unknown_pps(const uhd::time_spec_t& timespec) override + { + UHD_SAFE_C_SAVE_ERROR(this, + for (size_t i = 0; i < nof_radios; i++) { radio_ctrl[i]->set_time_next_pps(timespec); }); + } + uhd_error get_time_now(uhd::time_spec_t& timespec) override + { + UHD_SAFE_C_SAVE_ERROR(this, timespec = radio_ctrl[0]->get_time_now();); + } uhd_error set_sync_source(const std::string& source) override { sync_source = source; return UHD_ERROR_NONE; } + uhd_error get_gain_range(uhd::gain_range_t& tx_gain_range, uhd::gain_range_t& rx_gain_range) override + { + // Hard coded for X300 + tx_gain_range = uhd::gain_range_t(.0, 30.0, .5); + rx_gain_range = uhd::gain_range_t(.0, 30.0, .5); + 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; } @@ -484,4 +541,4 @@ public: }; #endif // SRSLTE_RF_UHD_RFNOC_H -#endif // UHD_VERSION == 3150000 \ No newline at end of file +#endif // UHD_VERSION == 3150000 diff --git a/lib/src/phy/rf/rf_uhd_safe.h b/lib/src/phy/rf/rf_uhd_safe.h index a0f4f9a28..43dc31a3f 100644 --- a/lib/src/phy/rf/rf_uhd_safe.h +++ b/lib/src/phy/rf/rf_uhd_safe.h @@ -21,6 +21,12 @@ #ifndef SRSLTE_RF_UHD_SAFE_H #define SRSLTE_RF_UHD_SAFE_H +#include +#define Warning(message) UHD_LOG_WARNING("UHD RF", message) +#define Info(message) UHD_LOG_INFO("UHD RF", message) +#define Debug(message) UHD_LOG_DEBUG("UHD RF", message) +#define Trace(message) UHD_LOG_TRACE("UHD RF", message) + #ifdef ENABLE_UHD_X300_FW_RESET #include @@ -29,14 +35,50 @@ uhd::wb_iface::sptr x300_make_ctrl_iface_enet(uhd::transport::udp_simple::sptr u class rf_uhd_safe_interface { +private: +#ifdef ENABLE_UHD_X300_FW_RESET + const double X300_SLEEP_TIME_S = 5.0; +#endif /* ENABLE_UHD_X300_FW_RESET */ + + virtual uhd_error usrp_make_internal(const uhd::device_addr_t& dev_addr) = 0; + +#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, + // It is not possible to reset device if IP address is not provided + if (not dev_addr.has_key("addr")) { return UHD_ERROR_NONE; } + + Warning("Reseting X300 in address " << dev_addr["addr"]); + + { // 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); + + Info("Reset Done!"); + x300_ctrl = nullptr; + udp_simple = nullptr; + } + + return UHD_ERROR_NONE;) + } +#endif /* ENABLE_UHD_X300_FW_RESET */ + protected: // List of errors that can happen in the USRP make that need to restart the device const std::set USRP_MAKE_RESET_ERR = {UHD_ERROR_IO}; // UHD pointers - uhd::usrp::multi_usrp::sptr usrp = nullptr; - uhd::rx_streamer::sptr rx_stream = nullptr; - uhd::tx_streamer::sptr tx_stream = nullptr; + uhd::rx_streamer::sptr rx_stream = nullptr; + uhd::tx_streamer::sptr tx_stream = nullptr; uhd_error usrp_multi_make(const uhd::device_addr_t& dev_addr) { @@ -55,7 +97,9 @@ protected: return err; } - sleep(5); + // Sleep for some time + Info("Wait " << std::to_string(X300_SLEEP_TIME_S) << " seconds"); + std::this_thread::sleep_for(std::chrono::milliseconds(int64_t(1000 * X300_SLEEP_TIME_S))); // Try opening the device one more time return usrp_make_internal(dev_addr); @@ -64,110 +108,56 @@ protected: #endif /* ENABLE_UHD_X300_FW_RESET */ } -private: - uhd_error usrp_make_internal(const uhd::device_addr_t& dev_addr) - { - // Destroy any previous USRP instance - usrp = nullptr; - - 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, - // 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;) - } -#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();) - } - inline uhd_error get_mboard_sensor_names(std::vector& sensors) - { - UHD_SAFE_C_SAVE_ERROR(this, sensors = usrp->get_mboard_sensor_names();) - } - inline uhd_error get_rx_sensor_names(std::vector& sensors) - { - UHD_SAFE_C_SAVE_ERROR(this, sensors = usrp->get_rx_sensor_names();) - } - inline uhd_error get_sensor(const std::string& sensor_name, uhd::sensor_value_t& sensor_value) - { - UHD_SAFE_C_SAVE_ERROR(this, sensor_value = usrp->get_mboard_sensor(sensor_name);) - } - inline uhd_error get_rx_sensor(const std::string& sensor_name, uhd::sensor_value_t& sensor_value) - { - UHD_SAFE_C_SAVE_ERROR(this, sensor_value = usrp->get_rx_sensor(sensor_name);) - } - 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) + 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; + virtual uhd_error get_mboard_name(std::string& mboard_name) = 0; + virtual uhd_error get_mboard_sensor_names(std::vector& sensors) = 0; + virtual uhd_error get_rx_sensor_names(std::vector& sensors) = 0; + virtual uhd_error get_sensor(const std::string& sensor_name, uhd::sensor_value_t& sensor_value) = 0; + virtual uhd_error get_rx_sensor(const std::string& sensor_name, uhd::sensor_value_t& sensor_value) = 0; + virtual uhd_error set_time_unknown_pps(const uhd::time_spec_t& timespec) = 0; + virtual uhd_error get_time_now(uhd::time_spec_t& timespec) = 0; + virtual uhd_error start_rx_stream(double delay) { + uhd::time_spec_t time_spec; + uhd_error err = get_time_now(time_spec); + if (err != UHD_ERROR_NONE) { + return err; + } + 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(); + stream_cmd.time_spec = time_spec; stream_cmd.time_spec += 0.1; stream_cmd.stream_now = false; rx_stream->issue_stream_cmd(stream_cmd);) } - inline uhd_error stop_rx_stream() + virtual uhd_error stop_rx_stream() { 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);) } - 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();) - } - 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 set_sync_source(const std::string& source) = 0; + virtual uhd_error get_gain_range(uhd::gain_range_t& tx_gain_range, uhd::gain_range_t& rx_gain_range) = 0; + 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; + virtual 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 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, + virtual uhd_error receive(void** buffs, const size_t nsamps_per_buff, uhd::rx_metadata_t& metadata, const double timeout, @@ -177,23 +167,21 @@ public: 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);) } - inline uhd_error recv_async_msg(uhd::async_metadata_t& async_metadata, double timeout, bool& valid) + virtual uhd_error recv_async_msg(uhd::async_metadata_t& async_metadata, double timeout, bool& valid) { - UHD_SAFE_C_SAVE_ERROR(this, valid = tx_stream->recv_async_msg(async_metadata, timeout); if (valid) { - return UHD_ERROR_NONE; - } valid = usrp.get()->get_device()->recv_async_msg(async_metadata);) + UHD_SAFE_C_SAVE_ERROR(this, valid = tx_stream->recv_async_msg(async_metadata, timeout);) } - inline uhd_error send(void** buffs, - const size_t nsamps_per_buff, - const uhd::tx_metadata_t& metadata, - const double timeout, - size_t& nof_txd_samples) + virtual uhd_error send(void** buffs, + const size_t nsamps_per_buff, + const uhd::tx_metadata_t& metadata, + const double timeout, + size_t& nof_txd_samples) { UHD_SAFE_C_SAVE_ERROR(this, uhd::tx_streamer::buffs_type buffs_cpp(buffs, tx_stream->get_num_channels()); nof_txd_samples = tx_stream->send(buffs_cpp, nsamps_per_buff, metadata, timeout);) } - inline bool is_rx_ready() { return rx_stream != nullptr; } - inline bool is_tx_ready() { return tx_stream != nullptr; } + virtual bool is_rx_ready() { return rx_stream != nullptr; } + virtual bool is_tx_ready() { return tx_stream != nullptr; } }; #endif // SRSLTE_RF_UHD_SAFE_H