Thanks for the reply and sorry for not providing much information. My case is that I want to do a relay transmission with the setup: USRP 1 transmits --> USRP 2 receives and retransmits with a shifted fc --> USRP 3 receives. The problem is in USRP 2, as you pointed out in your post. I'm testing on a simple flowgraph RX --> DDC --> DmaFIFO --> DUC (frequency shifted by 5MHz) --> TX. I used your approach [1] in step 1 of your tutorial (also did step 2 and 3) and rebuilt. At first the flowgraph runs without errors. The TX and RX lights were on, so it seemed to transmit something. But in USRP 3 I didn't see the relay signals (only the original signal that USRP1 transmits). Also, in the following runs, it raised the errors: [INFO] [UHDlinux; GNU C++ version 5.4.0 20160609; Boost_105800; UHD_4.0.0.rfnoc-devel-409-gec9138eb] [INFO] [X300] X300 initialization sequence... [INFO] [X300] Determining maximum frame size... [INFO] [X300] Maximum frame size: 1472 bytes. [INFO] [X300] Setup basic communication... [INFO] [X300] Loading values from EEPROM... [INFO] [X300] Setup RF frontend clocking... [INFO] [X300] Radio 1x clock:200 [INFO] [RFNOC] [DMA FIFO] Running BIST for FIFO 0... [INFO] [RFNOC] pass (Throughput: 1302.9MB/s) [INFO] [RFNOC] [DMA FIFO] Running BIST for FIFO 1... [INFO] [RFNOC] pass (Throughput: 1293.6MB/s) [INFO] [RFNOC RADIO] Register loopback test passed [INFO] [RFNOC RADIO] Register loopback test passed [INFO] [RFNOC RADIO] Register loopback test passed [INFO] [RFNOC RADIO] Register loopback test passed [INFO] [CORES] Performing timer loopback test... [INFO] [CORES] Timer loopback test passed [INFO] [CORES] Performing timer loopback test... [INFO] [CORES] Timer loopback test passed [INFO] [RFNOC] Assuming max packet size for 0/DDC_0 [INFO] [RFNOC] Assuming max packet size for 0/DmaFIFO_0 [INFO] [RFNOC] Assuming max packet size for 0/DUC_0 [INFO] [RFNOC] Assuming max packet size for 0/Radio_0 kei@kei-Precision-T7610:~/test_rfnoc$ ./relay.py [INFO] [UHDlinux; GNU C++ version 5.4.0 20160609; Boost_105800; UHD_4.0.0.rfnoc-devel-409-gec9138eb] [INFO] [X300] X300 initialization sequence... [INFO] [X300] Determining maximum frame size... [INFO] [X300] Maximum frame size: 1472 bytes. [INFO] [X300] Setup basic communication... [INFO] [X300] Loading values from EEPROM... [INFO] [X300] Setup RF frontend clocking... [INFO] [X300] Radio 1x clock:200 [ERROR] [UHD] Exception caught in safe-call. in virtual ctrl_iface_impl::~ctrl_iface_impl() at /home/kei/rfnoc/src/uhd/host/lib/rfnoc/ctrl_iface.cpp:76 this->peek32(0); -> EnvironmentError: IOError: Block ctrl (CE_00_Port_30) packet parse error - EnvironmentError: IOError: Expected packet index: 3 Received index: 4 Traceback (most recent call last): File "./relay.py", line 291, in <module> main() File "./relay.py", line 279, in main tb = top_block_cls(freq=options.freq) File "./relay.py", line 72, in __init__ self.device3 = device3 = ettus.device3(uhd.device_addr_t( ",".join(('type=x300', "")) )) File "/home/kei/rfnoc/lib/python2.7/dist-packages/ettus/ettus_swig.py", line 1610, in make return _ettus_swig.device3_make(device_addr) RuntimeError: EnvironmentError: IOError: [0/DmaFIFO_0] sr_read64() failed: EnvironmentError: IOError: Block ctrl (CE_00_Port_30) packet parse error - EnvironmentError: IOError: Expected SID: 02:30>00:00 Received SID: 02:c0>00:00
which is exactly the errors that Christophe faced in the previous post. I had to power cycle to run the flowgraph again. Attachments are the changed files. I'm using uhd version UHD 4.0.0.rfnoc-devel-409-gec9138eb and gnuradio version 3.7.12git-295-ga0adcd33. Sorry for the long post. On Fri, Mar 9, 2018 at 12:21 PM, Nick Foster <bistrom...@gmail.com> wrote: > You're going to have to ask a better question than that. Please provide > the following: > > * What you are trying to accomplish > * What hardware you are using > * What UHD and Gnuradio version you are using > * The approach you followed > * The result you expected > * The result you actually got > * A flowgraph which exhibits the problem > > If you put effort into your question, we can put effort into answering you. > > Nick > > On Thu, Mar 8, 2018 at 10:39 AM Kei Nguyen via USRP-users < > usrp-users@lists.ettus.com> wrote: > >> Hello, is this problem resolved? I am facing the same issue in the last >> email. Also, I tried to receive the relay signal with another usrp but it >> doesn't receive anything in my transmit frequency. >> >> Hai >> _______________________________________________ >> USRP-users mailing list >> USRP-users@lists.ettus.com >> http://lists.ettus.com/mailman/listinfo/usrp-users_lists.ettus.com >> >
#!/usr/bin/env python2 # -*- coding: utf-8 -*- ################################################## # GNU Radio Python Flow Graph # Title: Relay # Generated: Fri Mar 9 13:08:00 2018 ################################################## if __name__ == '__main__': import ctypes import sys if sys.platform.startswith('linux'): try: x11 = ctypes.cdll.LoadLibrary('libX11.so') x11.XInitThreads() except: print "Warning: failed to XInitThreads()" from PyQt4 import Qt from gnuradio import eng_notation from gnuradio import gr from gnuradio import uhd from gnuradio.eng_option import eng_option from gnuradio.filter import firdes from gnuradio.qtgui import Range, RangeWidget from optparse import OptionParser import ettus import sys from gnuradio import qtgui class relay(gr.top_block, Qt.QWidget): def __init__(self, freq=2412e6): gr.top_block.__init__(self, "Relay") Qt.QWidget.__init__(self) self.setWindowTitle("Relay") qtgui.util.check_set_qss() try: self.setWindowIcon(Qt.QIcon.fromTheme('gnuradio-grc')) except: pass self.top_scroll_layout = Qt.QVBoxLayout() self.setLayout(self.top_scroll_layout) self.top_scroll = Qt.QScrollArea() self.top_scroll.setFrameStyle(Qt.QFrame.NoFrame) self.top_scroll_layout.addWidget(self.top_scroll) self.top_scroll.setWidgetResizable(True) self.top_widget = Qt.QWidget() self.top_scroll.setWidget(self.top_widget) self.top_layout = Qt.QVBoxLayout(self.top_widget) self.top_grid_layout = Qt.QGridLayout() self.top_layout.addLayout(self.top_grid_layout) self.settings = Qt.QSettings("GNU Radio", "relay") self.restoreGeometry(self.settings.value("geometry").toByteArray()) ################################################## # Parameters ################################################## self.freq = freq ################################################## # Variables ################################################## self.samp_rate = samp_rate = 20e6 self.rx_gain = rx_gain = 20 self.rx_freq = rx_freq = 98100000 self.rx_digital_gain = rx_digital_gain = 1 self.master_clk_rate = master_clk_rate = 200e6 self.device3 = device3 = ettus.device3(uhd.device_addr_t( ",".join(('type=x300', "")) )) ################################################## # Blocks ################################################## self.uhd_rfnoc_streamer_radio_1 = ettus.rfnoc_radio( self.device3, uhd.stream_args( # Tx Stream Args cpu_format="fc32", otw_format="sc16", args='', ), uhd.stream_args( # Rx Stream Args cpu_format="fc32", otw_format="sc16", args="", # empty ), 0, -1 ) self.uhd_rfnoc_streamer_radio_1.set_rate(master_clk_rate) for i in xrange(1): self.uhd_rfnoc_streamer_radio_1.set_tx_freq(2412e6, i) self.uhd_rfnoc_streamer_radio_1.set_tx_gain(20, i) self.uhd_rfnoc_streamer_radio_1.set_tx_dc_offset(True, i) self.uhd_rfnoc_streamer_radio_1.set_tx_antenna("TX/RX", 0) self.uhd_rfnoc_streamer_radio_1.set_clock_source("internal") self.uhd_rfnoc_streamer_radio_0 = ettus.rfnoc_radio( self.device3, uhd.stream_args( # Tx Stream Args cpu_format="fc32", otw_format="sc16", args="", # empty ), uhd.stream_args( # Rx Stream Args cpu_format="fc32", otw_format="sc16", args='', ), 0, -1 ) self.uhd_rfnoc_streamer_radio_0.set_rate(master_clk_rate) for i in xrange(1): self.uhd_rfnoc_streamer_radio_0.set_rx_freq(freq, i) self.uhd_rfnoc_streamer_radio_0.set_rx_gain(20, i) self.uhd_rfnoc_streamer_radio_0.set_rx_dc_offset(True, i) self.uhd_rfnoc_streamer_radio_0.set_rx_bandwidth(56e6, 0) self.uhd_rfnoc_streamer_radio_0.set_rx_antenna("RX2", 0) self.uhd_rfnoc_streamer_radio_0.set_clock_source("internal") self.uhd_rfnoc_streamer_duc_0 = ettus.rfnoc_generic( self.device3, uhd.stream_args( # TX Stream Args cpu_format="fc32", # TODO: This must be made an option otw_format="sc16", args="input_rate={},output_rate={},fullscale={},freq={}".format(samp_rate, master_clk_rate, 1.0, 5e6), ), uhd.stream_args( # RX Stream Args cpu_format="fc32", # TODO: This must be made an option otw_format="sc16", args="", ), "DUC", -1, -1, ) self.uhd_rfnoc_streamer_dma_fifo_0 = ettus.rfnoc_generic( self.device3, uhd.stream_args( # TX Stream Args cpu_format="fc32", otw_format="sc16", args="gr_vlen={0},{1}".format(1, "" if 1 == 1 else "spp={0}".format(1)), ), uhd.stream_args( # RX Stream Args cpu_format="fc32", otw_format="sc16", args="gr_vlen={0},{1}".format(1, "" if 1 == 1 else "spp={0}".format(1)), ), "DmaFIFO", -1, -1, ) self.uhd_rfnoc_streamer_dma_fifo_0.set_arg("base_addr",0,0) self.uhd_rfnoc_streamer_dma_fifo_0.set_arg("depth",33554432,0) self.uhd_rfnoc_streamer_dma_fifo_0.set_arg("base_addr",33554432,1) self.uhd_rfnoc_streamer_dma_fifo_0.set_arg("depth",33554432,1) self.uhd_rfnoc_streamer_ddc_0 = ettus.rfnoc_generic( self.device3, uhd.stream_args( # TX Stream Args cpu_format="fc32", # TODO: This must be made an option otw_format="sc16", channels=range(1), args="input_rate={},output_rate={},fullscale={},freq={}".format(master_clk_rate, samp_rate, 1.0, 0), ), uhd.stream_args( # RX Stream Args cpu_format="fc32", # TODO: This must be made an option otw_format="sc16", channels=range(1), args="", ), "DDC", -1, -1, ) for chan in xrange(1): self.uhd_rfnoc_streamer_ddc_0.set_arg("input_rate", float(master_clk_rate), chan) self.uhd_rfnoc_streamer_ddc_0.set_arg("output_rate", float(samp_rate), chan) self.uhd_rfnoc_streamer_ddc_0.set_arg("fullscale", 1.0, chan) self.uhd_rfnoc_streamer_ddc_0.set_arg("freq", 0, chan) self._rx_gain_range = Range(0, 30, 1, 20, 200) self._rx_gain_win = RangeWidget(self._rx_gain_range, self.set_rx_gain, 'RX Gain', "counter_slider", float) self.top_layout.addWidget(self._rx_gain_win) self._rx_freq_range = Range(50000000, 6000000000, 1000000, 98100000, 200) self._rx_freq_win = RangeWidget(self._rx_freq_range, self.set_rx_freq, 'RX Frequency', "counter_slider", float) self.top_layout.addWidget(self._rx_freq_win) self._rx_digital_gain_range = Range(0, 30, 1, 1, 200) self._rx_digital_gain_win = RangeWidget(self._rx_digital_gain_range, self.set_rx_digital_gain, 'RX Digital Gain', "counter_slider", float) self.top_layout.addWidget(self._rx_digital_gain_win) ################################################## # Connections ################################################## self.device3.connect(self.uhd_rfnoc_streamer_ddc_0.get_block_id(), 0, self.uhd_rfnoc_streamer_dma_fifo_0.get_block_id(), 0) self.device3.connect(self.uhd_rfnoc_streamer_dma_fifo_0.get_block_id(), 0, self.uhd_rfnoc_streamer_duc_0.get_block_id(), 0) self.device3.connect(self.uhd_rfnoc_streamer_duc_0.get_block_id(), 0, self.uhd_rfnoc_streamer_radio_1.get_block_id(), 0) self.device3.connect(self.uhd_rfnoc_streamer_radio_0.get_block_id(), 0, self.uhd_rfnoc_streamer_ddc_0.get_block_id(), 0) #ADD THESE TO HANDLE ACTIVE STREAMER self.uhd_rfnoc_streamer_radio_0.set_rx_streamer(True, 0) stream_cmd = uhd.stream_cmd_t(uhd.stream_cmd_t.STREAM_MODE_START_CONTINUOUS) self.uhd_rfnoc_streamer_radio_0.issue_stream_cmd(stream_cmd) def closeEvent(self, event): self.settings = Qt.QSettings("GNU Radio", "relay") self.settings.setValue("geometry", self.saveGeometry()) event.accept() def get_freq(self): return self.freq def set_freq(self, freq): self.freq = freq for i in xrange(1): self.uhd_rfnoc_streamer_radio_0.set_rx_freq(self.freq, i) def get_samp_rate(self): return self.samp_rate def set_samp_rate(self, samp_rate): self.samp_rate = samp_rate self.uhd_rfnoc_streamer_duc_0.set_arg("input_rate", float(self.samp_rate)) for i in xrange(1): self.uhd_rfnoc_streamer_ddc_0.set_arg("output_rate", float(self.samp_rate), i) def get_rx_gain(self): return self.rx_gain def set_rx_gain(self, rx_gain): self.rx_gain = rx_gain def get_rx_freq(self): return self.rx_freq def set_rx_freq(self, rx_freq): self.rx_freq = rx_freq def get_rx_digital_gain(self): return self.rx_digital_gain def set_rx_digital_gain(self, rx_digital_gain): self.rx_digital_gain = rx_digital_gain def get_master_clk_rate(self): return self.master_clk_rate def set_master_clk_rate(self, master_clk_rate): self.master_clk_rate = master_clk_rate self.uhd_rfnoc_streamer_radio_1.set_rate(self.master_clk_rate) self.uhd_rfnoc_streamer_radio_0.set_rate(self.master_clk_rate) self.uhd_rfnoc_streamer_duc_0.set_arg("output_rate", float(self.master_clk_rate)) for i in xrange(1): self.uhd_rfnoc_streamer_ddc_0.set_arg("input_rate", float(self.master_clk_rate), i) def get_device3(self): return self.device3 def set_device3(self, device3): self.device3 = device3 def argument_parser(): parser = OptionParser(usage="%prog: [options]", option_class=eng_option) parser.add_option( "", "--freq", dest="freq", type="eng_float", default=eng_notation.num_to_str(2412e6), help="Set freq [default=%default]") return parser def main(top_block_cls=relay, options=None): if options is None: options, _ = argument_parser().parse_args() from distutils.version import StrictVersion if StrictVersion(Qt.qVersion()) >= StrictVersion("4.5.0"): style = gr.prefs().get_string('qtgui', 'style', 'raster') Qt.QApplication.setGraphicsSystem(style) qapp = Qt.QApplication(sys.argv) tb = top_block_cls(freq=options.freq) tb.start() tb.show() def quitting(): tb.stop() tb.wait() qapp.connect(qapp, Qt.SIGNAL("aboutToQuit()"), quitting) qapp.exec_() if __name__ == '__main__': main()
/* -*- c++ -*- */ /* Copyright 2015 Ettus Research * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * gr-ettus 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with gr-ettus; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ #ifndef INCLUDED_ETTUS_RFNOC_RADIO_H #define INCLUDED_ETTUS_RFNOC_RADIO_H #include <ettus/api.h> #include <ettus/device3.h> #include <ettus/rfnoc_block.h> #include <uhd/stream.hpp> #include <uhd/types/ranges.hpp> namespace gr { namespace ettus { /*! * \brief <+description of block+> * \ingroup ettus * */ class ETTUS_API rfnoc_radio : virtual public rfnoc_block { public: typedef boost::shared_ptr<rfnoc_radio> sptr; /*! * \brief Return a shared_ptr to a new instance of ettus::rfnoc_radio. * * To avoid accidental use of raw pointers, ettus::rfnoc_radio's * constructor is in a private implementation * class. ettus::rfnoc_radio::make is the public interface for * creating new instances. */ static sptr make( const device3::sptr &dev, const ::uhd::stream_args_t &tx_stream_args, const ::uhd::stream_args_t &rx_stream_args, const int radio_select, const int device_select=-1 ); virtual void set_rate(const double rate) = 0; virtual void set_tx_freq(const double freq, const size_t chan=0) = 0; virtual void set_rx_freq(const double freq, const size_t chan=0) = 0; virtual void set_tx_gain(const double gain, const size_t chan=0) = 0; virtual void set_rx_gain(const double gain, const size_t chan=0) = 0; virtual void set_tx_antenna(const std::string &ant, const size_t chan=0) = 0; virtual void set_rx_antenna(const std::string &ant, const size_t chan=0) = 0; virtual void set_tx_dc_offset(bool enable, const size_t chan=0) = 0; virtual void set_tx_dc_offset(const std::complex< double > &offset, const size_t chan=0) = 0; virtual void set_rx_dc_offset(bool enable, const size_t chan=0) = 0; virtual void set_rx_dc_offset(const std::complex< double > &offset, const size_t chan=0) = 0; virtual void set_rx_bandwidth(const double bandwidth, const size_t chan=0) = 0; // ADD THIS TO ENABLE ACTIVE STREAMER https://corvid.io/2017/04/22/stupid-rfnoc-tricks-loopback/ virtual void set_tx_streamer(bool active, const size_t port) = 0; virtual void set_rx_streamer(bool active, const size_t port) = 0; virtual void issue_stream_cmd(const uhd::stream_cmd_t &cmd, const size_t chan=0) = 0; virtual double get_rate() = 0; virtual double get_tx_freq(const size_t chan=0) = 0; virtual double get_rx_freq(const size_t chan=0) = 0; virtual double get_tx_gain(const size_t chan=0) = 0; virtual double get_rx_gain(const size_t chan=0) = 0; virtual std::string get_tx_antenna(const size_t chan=0) = 0; virtual std::string get_rx_antenna(const size_t chan=0) = 0; virtual std::vector<std::string> get_rx_lo_names(const size_t chan=0) = 0; virtual std::vector<std::string> get_rx_lo_sources(const std::string &name, const size_t chan=0) = 0; virtual uhd::freq_range_t get_rx_lo_freq_range(const std::string &name, const size_t chan=0) = 0; virtual void set_rx_lo_source(const std::string &src, const std::string &name, const size_t chan=0) = 0; virtual const std::string get_rx_lo_source(const std::string &name, const size_t chan=0) = 0; virtual void set_rx_lo_export_enabled(bool enabled, const std::string &name, const size_t chan=0) = 0; virtual bool get_rx_lo_export_enabled(const std::string &name, const size_t chan=0) = 0; virtual double set_rx_lo_freq(double freq, const std::string &name, const size_t chan=0) = 0; virtual double get_rx_lo_freq(const std::string &name, const size_t chan=0) = 0; virtual void set_clock_source(const std::string &source) = 0; virtual std::string get_clock_source() = 0; virtual std::vector<std::string> get_gpio_banks() const = 0; virtual void set_gpio_attr( const std::string &bank, const std::string &attr, const uint32_t value, const uint32_t mask ) = 0; virtual uint32_t get_gpio_attr(const std::string &bank, const std::string &attr) = 0; virtual void set_time_next_pps(const uhd::time_spec_t &spec) = 0; virtual uhd::time_spec_t get_time_now(void) = 0; virtual uhd::time_spec_t get_time_last_pps(void) = 0; virtual void set_command_time(const uhd::time_spec_t &time, const size_t chan=0) = 0; virtual void clear_command_time(const size_t chan=0) = 0; }; } // namespace ettus } // namespace gr #endif /* INCLUDED_ETTUS_RFNOC_RADIO_H */
/* -*- c++ -*- */ /* Copyright 2015 Ettus Research * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * gr-ettus 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with gr-ettus; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <gnuradio/io_signature.h> #include "rfnoc_radio_impl.h" namespace gr { namespace ettus { rfnoc_radio::sptr rfnoc_radio::make( const device3::sptr &dev, const ::uhd::stream_args_t &tx_stream_args, const ::uhd::stream_args_t &rx_stream_args, const int radio_select, const int device_select ) { return gnuradio::get_initial_sptr( new rfnoc_radio_impl(dev, tx_stream_args, rx_stream_args, radio_select, device_select) ); } rfnoc_radio_impl::rfnoc_radio_impl( const device3::sptr &dev, const ::uhd::stream_args_t &tx_stream_args, const ::uhd::stream_args_t &rx_stream_args, const int radio_select, const int device_select ) : rfnoc_block("rfnoc_radio"), rfnoc_block_impl( dev, rfnoc_block_impl::make_block_id("Radio", radio_select, device_select), tx_stream_args, rx_stream_args ) { _radio_ctrl = get_block_ctrl_throw< ::uhd::rfnoc::radio_ctrl >(); } rfnoc_radio_impl::~rfnoc_radio_impl() { /* nop */ } double rfnoc_radio_impl::get_rate() { return _radio_ctrl->get_rate(); } void rfnoc_radio_impl::set_rate(const double rate) { _radio_ctrl->set_rate(rate); } double rfnoc_radio_impl::get_tx_freq(const size_t chan) { return _radio_ctrl->get_tx_frequency(chan); } void rfnoc_radio_impl::set_tx_freq(const double freq, const size_t chan) { _radio_ctrl->set_tx_frequency(freq, chan); } double rfnoc_radio_impl::get_rx_freq(const size_t chan) { return _radio_ctrl->get_rx_frequency(chan); } void rfnoc_radio_impl::set_rx_freq(const double freq, const size_t chan) { _radio_ctrl->set_rx_frequency(freq, chan); } double rfnoc_radio_impl::get_tx_gain(const size_t chan) { return _radio_ctrl->get_tx_gain(chan); } void rfnoc_radio_impl::set_tx_gain(const double gain, const size_t chan) { _radio_ctrl->set_tx_gain(gain, chan); } double rfnoc_radio_impl::get_rx_gain(const size_t chan) { return _radio_ctrl->get_rx_gain(chan); } void rfnoc_radio_impl::set_rx_gain(const double gain, const size_t chan) { _radio_ctrl->set_rx_gain(gain, chan); } double rfnoc_radio_impl::get_rx_bandwidth(const size_t chan) { return _radio_ctrl->get_rx_bandwidth(chan); } void rfnoc_radio_impl::set_rx_bandwidth(const double bandwidth, const size_t chan) { _radio_ctrl->set_rx_bandwidth(bandwidth, chan); } std::string rfnoc_radio_impl::get_tx_antenna(const size_t chan) { return _radio_ctrl->get_tx_antenna(chan); } void rfnoc_radio_impl::set_tx_antenna(const std::string &ant, const size_t chan) { _radio_ctrl->set_tx_antenna(ant, chan); } std::string rfnoc_radio_impl::get_rx_antenna(const size_t chan) { return _radio_ctrl->get_rx_antenna(chan); } void rfnoc_radio_impl::set_rx_antenna(const std::string &ant, const size_t chan) { _radio_ctrl->set_rx_antenna(ant, chan); } //ADD THESE TO ENABLE ACTIVE STREAMING https://corvid.io/2017/04/22/stupid-rfnoc-tricks-loopback/ void rfnoc_radio_impl::set_tx_streamer(bool active, const size_t port) { _radio_ctrl->set_tx_streamer(active, port); } void rfnoc_radio_impl::set_rx_streamer(bool active, const size_t port) { _radio_ctrl->set_rx_streamer(active, port); } void rfnoc_radio_impl::issue_stream_cmd(const uhd::stream_cmd_t &cmd, const size_t chan) { _radio_ctrl->issue_stream_cmd(cmd, chan); } // FIXME everything down from here needs to be mapped on to the block API void rfnoc_radio_impl::set_tx_dc_offset(bool enable, const size_t chan) { //get_device()->set_tx_dc_offset(enable, chan); } void rfnoc_radio_impl::set_tx_dc_offset(const std::complex< double > &offset, const size_t chan) { //get_device()->set_tx_dc_offset(offset, chan); } void rfnoc_radio_impl::set_rx_dc_offset(bool enable, const size_t chan) { //get_device()->set_rx_dc_offset(enable, chan); } void rfnoc_radio_impl::set_rx_dc_offset(const std::complex< double > &offset, const size_t chan) { //get_device()->set_rx_dc_offset(offset, chan); } std::vector<std::string> rfnoc_radio_impl::get_rx_lo_names(const size_t chan) { return _radio_ctrl->get_rx_lo_names(chan); } std::vector<std::string> rfnoc_radio_impl::get_rx_lo_sources(const std::string &name, const size_t chan) { return _radio_ctrl->get_rx_lo_sources(name, chan); } uhd::freq_range_t rfnoc_radio_impl::get_rx_lo_freq_range(const std::string &name, const size_t chan) { return _radio_ctrl->get_rx_lo_freq_range(name, chan); } void rfnoc_radio_impl::set_rx_lo_source(const std::string &src, const std::string &name, const size_t chan) { _radio_ctrl->set_rx_lo_source(src, name, chan); } const std::string rfnoc_radio_impl::get_rx_lo_source(const std::string &name, const size_t chan) { return _radio_ctrl->get_rx_lo_source(name, chan); } void rfnoc_radio_impl::set_rx_lo_export_enabled(bool enabled, const std::string &name, const size_t chan) { _radio_ctrl->set_rx_lo_export_enabled(enabled, "all", chan); } bool rfnoc_radio_impl::get_rx_lo_export_enabled(const std::string &name, const size_t chan) { return _radio_ctrl->get_rx_lo_export_enabled(name, chan); } double rfnoc_radio_impl::set_rx_lo_freq(double freq, const std::string &name, const size_t chan) { return _radio_ctrl->set_rx_lo_freq(freq, name, chan); } double rfnoc_radio_impl::get_rx_lo_freq(const std::string &name, const size_t chan) { return _radio_ctrl->get_rx_lo_freq(name, chan); } void rfnoc_radio_impl::set_clock_source(const std::string &source) { _radio_ctrl->set_clock_source(source); } std::string rfnoc_radio_impl::get_clock_source() { return _radio_ctrl->get_clock_source(); } std::vector<std::string> rfnoc_radio_impl::get_gpio_banks() const { return _radio_ctrl->get_gpio_banks(); } void rfnoc_radio_impl::set_gpio_attr( const std::string &bank, const std::string &attr, const uint32_t value, const uint32_t mask ) { _radio_ctrl->set_gpio_attr(bank, attr, value, mask); } uint32_t rfnoc_radio_impl::get_gpio_attr(const std::string &bank, const std::string &attr) { return _radio_ctrl->get_gpio_attr(bank, attr); } void rfnoc_radio_impl::set_time_next_pps(const uhd::time_spec_t &spec) { _radio_ctrl->set_time_next_pps(spec); } uhd::time_spec_t rfnoc_radio_impl::get_time_now(void) { return _radio_ctrl->get_time_now(); } uhd::time_spec_t rfnoc_radio_impl::get_time_last_pps(void) { return _radio_ctrl->get_time_last_pps(); } uhd::time_spec_t rfnoc_radio_impl::get_command_time(const size_t chan) { return _radio_ctrl->get_command_time(chan); } void rfnoc_radio_impl::set_command_time(const uhd::time_spec_t &time, const size_t chan) { _radio_ctrl->set_command_time(time, chan); } void rfnoc_radio_impl::clear_command_time(const size_t chan) { _radio_ctrl->clear_command_time(chan); } void rfnoc_radio_impl::set_command_tick_rate(const double tick_rate, const size_t chan) { _radio_ctrl->set_command_tick_rate(chan); } } /* namespace ettus */ } /* namespace gr */
/* -*- c++ -*- */ /* Copyright 2015 Ettus Research * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * gr-ettus 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with gr-ettus; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ #ifndef INCLUDED_ETTUS_RFNOC_RADIO_IMPL_H #define INCLUDED_ETTUS_RFNOC_RADIO_IMPL_H #include <ettus/rfnoc_radio.h> #include <ettus/rfnoc_block_impl.h> #include <uhd/rfnoc/radio_ctrl.hpp> #include <uhd/types/ranges.hpp> namespace gr { namespace ettus { class rfnoc_radio_impl : public rfnoc_radio, public rfnoc_block_impl { public: rfnoc_radio_impl( const device3::sptr &dev, const ::uhd::stream_args_t &tx_stream_args, const ::uhd::stream_args_t &rx_stream_args, const int radio_select, const int device_select ); ~rfnoc_radio_impl(); double get_rate(); double get_tx_freq(const size_t chan); double get_rx_freq(const size_t chan); double get_tx_gain(const size_t chan); double get_rx_gain(const size_t chan); double get_rx_bandwidth(const size_t chan); std::string get_tx_antenna(const size_t chan); std::string get_rx_antenna(const size_t chan); void set_rate(const double rate); void set_tx_freq(const double freq, const size_t chan); void set_rx_freq(const double freq, const size_t chan); void set_tx_gain(const double gain, const size_t chan); void set_rx_gain(const double gain, const size_t chan); void set_rx_bandwidth(const double bandwidth, const size_t chan); void set_tx_antenna(const std::string &ant, const size_t chan); void set_rx_antenna(const std::string &ant, const size_t chan); void set_tx_dc_offset(bool enable, const size_t chan); void set_tx_dc_offset(const std::complex< double > &offset, const size_t chan); void set_rx_dc_offset(bool enable, const size_t chan); void set_rx_dc_offset(const std::complex< double > &offset, const size_t chan); // ADD THESE TO ENABLE ACTIVE STREAMING https://corvid.io/2017/04/22/stupid-rfnoc-tricks-loopback/ void set_tx_streamer(bool active, const size_t port); void set_rx_streamer(bool active, const size_t port); void issue_stream_cmd(const uhd::stream_cmd_t &cmd, const size_t chan=0); std::vector<std::string> get_rx_lo_names(const size_t chan); std::vector<std::string> get_rx_lo_sources(const std::string &name, const size_t chan); uhd::freq_range_t get_rx_lo_freq_range(const std::string &name, const size_t chan); void set_rx_lo_source(const std::string &src, const std::string &name, const size_t chan); const std::string get_rx_lo_source(const std::string &name, const size_t chan); void set_rx_lo_export_enabled(bool enabled, const std::string &name, const size_t chan); bool get_rx_lo_export_enabled(const std::string &name, const size_t chan); double set_rx_lo_freq(double freq, const std::string &name, const size_t chan); double get_rx_lo_freq(const std::string &name, const size_t chan); void set_clock_source(const std::string &source); std::string get_clock_source(); std::vector<std::string> get_gpio_banks() const; void set_gpio_attr( const std::string &bank, const std::string &attr, const uint32_t value, const uint32_t mask ); uint32_t get_gpio_attr(const std::string &bank, const std::string &attr); void set_command_tick_rate(const double tick_rate, const size_t chan); uhd::time_spec_t get_time_now(void); uhd::time_spec_t get_time_last_pps(void); void set_time_next_pps(const uhd::time_spec_t &spec); uhd::time_spec_t get_command_time(const size_t chan); void set_command_time(const uhd::time_spec_t &time, const size_t chan); void clear_command_time(const size_t chan); private: ::uhd::rfnoc::radio_ctrl::sptr _radio_ctrl; bool _start_time_set = false; uhd::time_spec_t _start_time; }; } // namespace ettus } // namespace gr #endif /* INCLUDED_ETTUS_RFNOC_RADIO_IMPL_H */
// // Copyright 2014-2016 Ettus Research LLC // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program 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 General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // #include "wb_iface_adapter.hpp" #include <boost/format.hpp> #include <boost/bind.hpp> #include <uhd/convert.hpp> #include <uhd/utils/log.hpp> #include <uhd/types/ranges.hpp> #include <uhd/types/direction.hpp> #include "radio_ctrl_impl.hpp" #include "../../transport/super_recv_packet_handler.hpp" using namespace uhd; using namespace uhd::rfnoc; static const size_t BYTES_PER_SAMPLE = 4; const std::string radio_ctrl::ALL_LOS = "all"; /**************************************************************************** * Structors and init ***************************************************************************/ // Note: block_ctrl_base must be called before this, but has to be called by // the derived class because of virtual inheritance radio_ctrl_impl::radio_ctrl_impl() : _tick_rate(rfnoc::rate_node_ctrl::RATE_UNDEFINED) { _num_rx_channels = get_output_ports().size(); _num_tx_channels = get_input_ports().size(); _continuous_streaming = std::vector<bool>(2, false); for (size_t i = 0; i < _num_rx_channels; i++) { _rx_streamer_active[i] = false; } for (size_t i = 0; i < _num_tx_channels; i++) { _tx_streamer_active[i] = false; } ///////////////////////////////////////////////////////////////////////// // Setup peripherals ///////////////////////////////////////////////////////////////////////// for (size_t i = 0; i < _get_num_radios(); i++) { _register_loopback_self_test(i); _perifs[i].ctrl = boost::make_shared<wb_iface_adapter>( // poke32 functor boost::bind( static_cast< void (block_ctrl_base::*)(const uint32_t, const uint32_t, const size_t) >(&block_ctrl_base::sr_write), this, _1, _2, i ), // peek32 functor boost::bind( static_cast< uint32_t (block_ctrl_base::*)(const uint32_t, const size_t) >(&block_ctrl_base::user_reg_read32), this, _1, i ), // peek64 functor boost::bind( static_cast< uint64_t (block_ctrl_base::*)(const uint32_t, const size_t) >(&block_ctrl_base::user_reg_read64), this, _1, i ), // get_time functor boost::bind( static_cast< time_spec_t (block_ctrl_base::*)(const size_t) >(&block_ctrl_base::get_command_time), this, i ), // set_time functor boost::bind( static_cast< void (block_ctrl_base::*)(const time_spec_t&, const size_t) >(&block_ctrl_base::set_command_time), this, _1, i ) ); // FIXME there's currently no way to set the underflow policy if (i == 0) { time_core_3000::readback_bases_type time64_rb_bases; time64_rb_bases.rb_now = regs::RB_TIME_NOW; time64_rb_bases.rb_pps = regs::RB_TIME_PPS; _time64 = time_core_3000::make(_perifs[i].ctrl, regs::sr_addr(regs::TIME), time64_rb_bases); this->set_time_now(0.0); } //Reset the RX control engine sr_write(regs::RX_CTRL_HALT, 1, i); } //////////////////////////////////////////////////////////////////// // Register the time keeper //////////////////////////////////////////////////////////////////// if (not _tree->exists(fs_path("time") / "now")) { _tree->create<time_spec_t>(fs_path("time") / "now") .set_publisher(boost::bind(&radio_ctrl_impl::get_time_now, this)) ; } if (not _tree->exists(fs_path("time") / "pps")) { _tree->create<time_spec_t>(fs_path("time") / "pps") .set_publisher(boost::bind(&radio_ctrl_impl::get_time_last_pps, this)) ; } if (not _tree->exists(fs_path("time") / "cmd")) { _tree->create<time_spec_t>(fs_path("time") / "cmd"); } _tree->access<time_spec_t>(fs_path("time") / "now") .add_coerced_subscriber(boost::bind(&radio_ctrl_impl::set_time_now, this, _1)) ; _tree->access<time_spec_t>(fs_path("time") / "pps") .add_coerced_subscriber(boost::bind(&radio_ctrl_impl::set_time_next_pps, this, _1)) ; for (size_t i = 0; i < _get_num_radios(); i++) { _tree->access<time_spec_t>("time/cmd") .add_coerced_subscriber(boost::bind(&block_ctrl_base::set_command_tick_rate, this, boost::ref(_tick_rate), i)) .add_coerced_subscriber(boost::bind(&block_ctrl_base::set_command_time, this, _1, i)) ; } // spp gets created in the XML file _tree->access<int>(get_arg_path("spp") / "value") .add_coerced_subscriber(boost::bind(&radio_ctrl_impl::_update_spp, this, _1)) .update() ; } void radio_ctrl_impl::_register_loopback_self_test(size_t chan) { size_t hash = size_t(time(NULL)); for (size_t i = 0; i < 100; i++) { boost::hash_combine(hash, i); sr_write(regs::TEST, uint32_t(hash), chan); uint32_t result = user_reg_read32(regs::RB_TEST, chan); if (result != uint32_t(hash)) { UHD_LOGGER_ERROR("RFNOC RADIO") << "Register loopback test failed"; UHD_LOGGER_ERROR("RFNOC RADIO") << boost::format("expected: %x result: %x") % uint32_t(hash) % result ; return; // exit on any failure } } UHD_LOGGER_INFO("RFNOC RADIO") << "Register loopback test passed"; } /**************************************************************************** * API calls ***************************************************************************/ double radio_ctrl_impl::set_rate(double rate) { boost::mutex::scoped_lock lock(_mutex); _tick_rate = rate; _time64->set_tick_rate(_tick_rate); _time64->self_test(); set_command_tick_rate(rate); return _tick_rate; } void radio_ctrl_impl::set_tx_antenna(const std::string &ant, const size_t chan) { _tx_antenna[chan] = ant; } void radio_ctrl_impl::set_rx_antenna(const std::string &ant, const size_t chan) { _rx_antenna[chan] = ant; } double radio_ctrl_impl::set_tx_frequency(const double freq, const size_t chan) { return _tx_freq[chan] = freq; } double radio_ctrl_impl::set_rx_frequency(const double freq, const size_t chan) { return _rx_freq[chan] = freq; } double radio_ctrl_impl::set_tx_gain(const double gain, const size_t chan) { return _tx_gain[chan] = gain; } double radio_ctrl_impl::set_rx_gain(const double gain, const size_t chan) { return _rx_gain[chan] = gain; } double radio_ctrl_impl::set_rx_bandwidth(const double bandwidth, const size_t chan) { return _rx_bandwidth[chan] = bandwidth; } void radio_ctrl_impl::set_time_sync(const uhd::time_spec_t &time) { _time64->set_time_sync(time); } double radio_ctrl_impl::get_rate() const { return _tick_rate; } std::string radio_ctrl_impl::get_tx_antenna(const size_t chan) /* const */ { return _tx_antenna[chan]; } std::string radio_ctrl_impl::get_rx_antenna(const size_t chan) /* const */ { return _rx_antenna[chan]; } double radio_ctrl_impl::get_tx_frequency(const size_t chan) /* const */ { return _tx_freq[chan]; } double radio_ctrl_impl::get_rx_frequency(const size_t chan) /* const */ { return _rx_freq[chan]; } double radio_ctrl_impl::get_tx_gain(const size_t chan) /* const */ { return _tx_gain[chan]; } double radio_ctrl_impl::get_rx_gain(const size_t chan) /* const */ { return _rx_gain[chan]; } double radio_ctrl_impl::get_rx_bandwidth(const size_t chan) /* const */ { return _rx_bandwidth[chan]; } std::vector<std::string> radio_ctrl_impl::get_rx_lo_names(const size_t /* chan */) { return std::vector<std::string>(); } std::vector<std::string> radio_ctrl_impl::get_rx_lo_sources(const std::string & /* name */, const size_t /* chan */) { return std::vector<std::string>(); } freq_range_t radio_ctrl_impl::get_rx_lo_freq_range(const std::string & /* name */, const size_t /* chan */) { return freq_range_t(); } void radio_ctrl_impl::set_rx_lo_source(const std::string & /* src */, const std::string & /* name */, const size_t /* chan */) { throw uhd::not_implemented_error("set_rx_lo_source is not supported on this radio"); } const std::string radio_ctrl_impl::get_rx_lo_source(const std::string & /* name */, const size_t /* chan */) { return "internal"; } void radio_ctrl_impl::set_rx_lo_export_enabled(bool /* enabled */, const std::string & /* name */, const size_t /* chan */) { throw uhd::not_implemented_error("set_rx_lo_export_enabled is not supported on this radio"); } bool radio_ctrl_impl::get_rx_lo_export_enabled(const std::string & /* name */, const size_t /* chan */) { return false; // Not exporting non-existant LOs } double radio_ctrl_impl::set_rx_lo_freq(double /* freq */, const std::string & /* name */, const size_t /* chan */) { throw uhd::not_implemented_error("set_rx_lo_freq is not supported on this radio"); } double radio_ctrl_impl::get_rx_lo_freq(const std::string & /* name */, const size_t /* chan */) { return 0; } /*********************************************************************** * RX Streamer-related methods (from source_block_ctrl_base) **********************************************************************/ //! Pass stream commands to the radio void radio_ctrl_impl::issue_stream_cmd(const uhd::stream_cmd_t &stream_cmd, const size_t chan) { boost::mutex::scoped_lock lock(_mutex); UHD_RFNOC_BLOCK_TRACE() << "radio_ctrl_impl::issue_stream_cmd() " << chan << " " << char(stream_cmd.stream_mode) ; if (not _is_streamer_active(uhd::RX_DIRECTION, chan)) { UHD_RFNOC_BLOCK_TRACE() << "radio_ctrl_impl::issue_stream_cmd() called on inactive channel. Skipping." ; return; } UHD_ASSERT_THROW(stream_cmd.num_samps <= 0x0fffffff); _continuous_streaming[chan] = (stream_cmd.stream_mode == stream_cmd_t::STREAM_MODE_START_CONTINUOUS); //setup the mode to instruction flags typedef boost::tuple<bool, bool, bool, bool> inst_t; static const uhd::dict<stream_cmd_t::stream_mode_t, inst_t> mode_to_inst = boost::assign::map_list_of //reload, chain, samps, stop (stream_cmd_t::STREAM_MODE_START_CONTINUOUS, inst_t(true, true, false, false)) (stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS, inst_t(false, false, false, true)) (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE, inst_t(false, false, true, false)) (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE, inst_t(false, true, true, false)) ; //setup the instruction flag values bool inst_reload, inst_chain, inst_samps, inst_stop; boost::tie(inst_reload, inst_chain, inst_samps, inst_stop) = mode_to_inst[stream_cmd.stream_mode]; //calculate the word from flags and length uint32_t cmd_word = 0; cmd_word |= uint32_t((stream_cmd.stream_now)? 1 : 0) << 31; cmd_word |= uint32_t((inst_chain)? 1 : 0) << 30; cmd_word |= uint32_t((inst_reload)? 1 : 0) << 29; cmd_word |= uint32_t((inst_stop)? 1 : 0) << 28; cmd_word |= (inst_samps)? stream_cmd.num_samps : ((inst_stop)? 0 : 1); //WRITE THIS TO DISABLE RX TIMESTAMPING https://corvid.io/2017/04/22/stupid-rfnoc-tricks-loopback/ sr_write(regs::RX_CTRL_OUTPUT_FORMAT, boost::uint32_t(0), chan); //issue the stream command const uint64_t ticks = (stream_cmd.stream_now)? 0 : stream_cmd.time_spec.to_ticks(get_rate()); sr_write(regs::RX_CTRL_CMD, cmd_word, chan); sr_write(regs::RX_CTRL_TIME_HI, uint32_t(ticks >> 32), chan); sr_write(regs::RX_CTRL_TIME_LO, uint32_t(ticks >> 0), chan); //latches the command } std::vector<size_t> radio_ctrl_impl::get_active_rx_ports() { std::vector<size_t> active_rx_ports; typedef std::map<size_t, bool> map_t; for(map_t::value_type &m: _rx_streamer_active) { if (m.second) { active_rx_ports.push_back(m.first); } } return active_rx_ports; } /*********************************************************************** * Radio controls (radio_ctrl specific) **********************************************************************/ void radio_ctrl_impl::set_rx_streamer(bool active, const size_t port) { UHD_RFNOC_BLOCK_TRACE() << "radio_ctrl_impl::set_rx_streamer() " << port << " -> " << active ; if (port > _num_rx_channels) { throw uhd::value_error(str( boost::format("[%s] Can't (un)register RX streamer on port %d (invalid port)") % unique_id() % port )); } _rx_streamer_active[port] = active; if (not check_radio_config()) { throw std::runtime_error(str( boost::format("[%s]: Invalid radio configuration.") % unique_id() )); } } void radio_ctrl_impl::set_tx_streamer(bool active, const size_t port) { UHD_RFNOC_BLOCK_TRACE() << "radio_ctrl_impl::set_tx_streamer() " << port << " -> " << active ; if (port > _num_tx_channels) { throw uhd::value_error(str( boost::format("[%s] Can't (un)register TX streamer on port %d (invalid port)") % unique_id() % port )); } _tx_streamer_active[port] = active; if (not check_radio_config()) { throw std::runtime_error(str( boost::format("[%s]: Invalid radio configuration.") % unique_id() )); } } // Subscribers to block args: // TODO move to nocscript void radio_ctrl_impl::_update_spp(int spp) { boost::mutex::scoped_lock lock(_mutex); UHD_RFNOC_BLOCK_TRACE() << "radio_ctrl_impl::_update_spp(): Requested spp: " << spp ; if (spp == 0) { spp = DEFAULT_PACKET_SIZE / BYTES_PER_SAMPLE; } UHD_RFNOC_BLOCK_TRACE() << "radio_ctrl_impl::_update_spp(): Setting spp to: " << spp ; for (size_t i = 0; i < _num_rx_channels; i++) { sr_write(regs::RX_CTRL_MAXLEN, uint32_t(spp), i); } } void radio_ctrl_impl::set_time_now(const time_spec_t &time_spec) { _time64->set_time_now(time_spec); } void radio_ctrl_impl::set_time_next_pps(const time_spec_t &time_spec) { _time64->set_time_next_pps(time_spec); } time_spec_t radio_ctrl_impl::get_time_now() { return _time64->get_time_now(); } time_spec_t radio_ctrl_impl::get_time_last_pps() { return _time64->get_time_last_pps(); } void radio_ctrl_impl::set_time_source(const std::string &source) { _tree->access<std::string>("time_source/value").set(source); } std::string radio_ctrl_impl::get_time_source() { return _tree->access<std::string>("time_source/value").get(); } std::vector<std::string> radio_ctrl_impl::get_time_sources() { return _tree->access<std::vector<std::string>>("time_source/options").get(); } void radio_ctrl_impl::set_clock_source(const std::string &source) { _tree->access<std::string>("clock_source/value").set(source); } std::string radio_ctrl_impl::get_clock_source() { return _tree->access<std::string>("clock_source/value").get(); } std::vector<std::string> radio_ctrl_impl::get_clock_sources() { return _tree->access<std::vector<std::string>>("clock_source/options").get(); } std::vector<std::string> radio_ctrl_impl::get_gpio_banks() const { return std::vector<std::string>(); } void radio_ctrl_impl::set_gpio_attr( const std::string &, const std::string &, const uint32_t, const uint32_t ) { throw uhd::not_implemented_error("set_gpio_attr was not defined for this radio"); } uint32_t radio_ctrl_impl::get_gpio_attr(const std::string &, const std::string &) { throw uhd::not_implemented_error("get_gpio_attr was not defined for this radio"); }
// // Copyright 2014-2016 Ettus Research LLC // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program 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 General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. // #ifndef INCLUDED_LIBUHD_RFNOC_RADIO_CTRL_IMPL_HPP #define INCLUDED_LIBUHD_RFNOC_RADIO_CTRL_IMPL_HPP #include "rx_vita_core_3000.hpp" #include "tx_vita_core_3000.hpp" #include "time_core_3000.hpp" #include "gpio_atr_3000.hpp" #include <uhd/rfnoc/radio_ctrl.hpp> #include <uhd/types/direction.hpp> #include <boost/thread.hpp> //! Shorthand for radio block constructor #define UHD_RFNOC_RADIO_BLOCK_CONSTRUCTOR_DECL(CLASS_NAME) \ CLASS_NAME##_impl(const make_args_t &make_args); #define UHD_RFNOC_RADIO_BLOCK_CONSTRUCTOR(CLASS_NAME) \ CLASS_NAME##_impl::CLASS_NAME##_impl( \ const make_args_t &make_args \ ) : block_ctrl_base(make_args), radio_ctrl_impl() namespace uhd { namespace rfnoc { /*! \brief Provide access to a radio. * */ class radio_ctrl_impl : public radio_ctrl { public: /************************************************************************ * Structors ***********************************************************************/ radio_ctrl_impl(); virtual ~radio_ctrl_impl() {}; /************************************************************************ * Public Radio API calls ***********************************************************************/ virtual double set_rate(double rate); virtual void set_tx_antenna(const std::string &ant, const size_t chan); virtual void set_rx_antenna(const std::string &ant, const size_t chan); virtual double set_tx_frequency(const double freq, const size_t chan); virtual double set_rx_frequency(const double freq, const size_t chan); virtual double set_tx_gain(const double gain, const size_t chan); virtual double set_rx_gain(const double gain, const size_t chan); virtual double set_rx_bandwidth(const double bandwidth, const size_t chan); virtual double get_rate() const; virtual std::string get_tx_antenna(const size_t chan) /* const */; virtual std::string get_rx_antenna(const size_t chan) /* const */; virtual double get_tx_frequency(const size_t) /* const */; virtual double get_rx_frequency(const size_t) /* const */; virtual double get_tx_gain(const size_t) /* const */; virtual double get_rx_gain(const size_t) /* const */; virtual double get_rx_bandwidth(const size_t) /* const */; virtual std::vector<std::string> get_rx_lo_names(const size_t chan); virtual std::vector<std::string> get_rx_lo_sources(const std::string &name, const size_t chan); virtual freq_range_t get_rx_lo_freq_range(const std::string &name, const size_t chan); virtual void set_rx_lo_source(const std::string &src, const std::string &name, const size_t chan); virtual const std::string get_rx_lo_source(const std::string &name, const size_t chan); virtual void set_rx_lo_export_enabled(bool enabled, const std::string &name, const size_t chan); virtual bool get_rx_lo_export_enabled(const std::string &name, const size_t chan); virtual double set_rx_lo_freq(double freq, const std::string &name, const size_t chan); virtual double get_rx_lo_freq(const std::string &name, const size_t chan); void set_time_now(const time_spec_t &time_spec); void set_time_next_pps(const time_spec_t &time_spec); void set_time_sync(const uhd::time_spec_t &time); time_spec_t get_time_now(); time_spec_t get_time_last_pps(); virtual void set_time_source(const std::string &source); virtual std::string get_time_source(); virtual std::vector<std::string> get_time_sources(); virtual void set_clock_source(const std::string &source); virtual std::string get_clock_source(); virtual std::vector<std::string> get_clock_sources(); virtual std::vector<std::string> get_gpio_banks() const; virtual void set_gpio_attr( const std::string &bank, const std::string &attr, const uint32_t value, const uint32_t mask ); virtual uint32_t get_gpio_attr(const std::string &bank, const std::string &attr); /*********************************************************************** * Block control API calls **********************************************************************/ void set_rx_streamer(bool active, const size_t port); void set_tx_streamer(bool active, const size_t port); void issue_stream_cmd(const uhd::stream_cmd_t &stream_cmd, const size_t port); virtual double get_input_samp_rate(size_t /* port */) { return get_rate(); } virtual double get_output_samp_rate(size_t /* port */) { return get_rate(); } double _get_tick_rate() { return get_rate(); } std::vector<size_t> get_active_rx_ports(); bool in_continuous_streaming_mode(const size_t chan) { return _continuous_streaming.at(chan); } void rx_ctrl_clear_cmds(const size_t port) { sr_write(regs::RX_CTRL_CLEAR_CMDS, 0, port); } protected: // TODO see what's protected and what's private void _register_loopback_self_test(size_t chan); /*********************************************************************** * Registers **********************************************************************/ struct regs { static inline uint32_t sr_addr(const uint32_t offset) { return offset * 4; } static const uint32_t BASE = 128; // defined in radio_core_regs.vh static const uint32_t TIME = 128; // time hi - 128, time lo - 129, ctrl - 130 static const uint32_t CLEAR_CMDS = 131; // Any write to this reg clears the command FIFO static const uint32_t LOOPBACK = 132; static const uint32_t TEST = 133; static const uint32_t CODEC_IDLE = 134; static const uint32_t TX_CTRL_ERROR_POLICY = 144; static const uint32_t RX_CTRL_CMD = 152; static const uint32_t RX_CTRL_TIME_HI = 153; static const uint32_t RX_CTRL_TIME_LO = 154; static const uint32_t RX_CTRL_HALT = 155; static const uint32_t RX_CTRL_MAXLEN = 156; static const uint32_t RX_CTRL_CLEAR_CMDS = 157; static const uint32_t RX_CTRL_OUTPUT_FORMAT= 158; //ADD THIS TO DISABLE RX TIMESTAMP https://corvid.io/2017/04/22/stupid-rfnoc-tricks-loopback/ static const uint32_t MISC_OUTS = 160; static const uint32_t DACSYNC = 161; static const uint32_t SPI = 168; static const uint32_t LEDS = 176; static const uint32_t FP_GPIO = 184; static const uint32_t GPIO = 192; // NOTE: Upper 32 registers (224-255) are reserved for the output settings bus for use with // device specific front end control // frontend control: needs rethinking TODO //static const uint32_t TX_FRONT = BASE + 96; //static const uint32_t RX_FRONT = BASE + 112; //static const uint32_t READBACK = BASE + 127; static const uint32_t RB_TIME_NOW = 0; static const uint32_t RB_TIME_PPS = 1; static const uint32_t RB_TEST = 2; static const uint32_t RB_CODEC_READBACK = 3; static const uint32_t RB_RADIO_NUM = 4; static const uint32_t RB_MISC_IO = 16; static const uint32_t RB_SPI = 17; static const uint32_t RB_LEDS = 18; static const uint32_t RB_DB_GPIO = 19; static const uint32_t RB_FP_GPIO = 20; }; /*********************************************************************** * Block control API calls **********************************************************************/ void _update_spp(int spp); inline size_t _get_num_radios() const { return std::max(_num_rx_channels, _num_tx_channels); } inline timed_wb_iface::sptr _get_ctrl(size_t radio_num) const { return _perifs.at(radio_num).ctrl; } inline bool _is_streamer_active(uhd::direction_t dir, const size_t chan) const { switch (dir) { case uhd::TX_DIRECTION: return _tx_streamer_active.at(chan); case uhd::RX_DIRECTION: return _rx_streamer_active.at(chan); case uhd::DX_DIRECTION: return _rx_streamer_active.at(chan) and _tx_streamer_active.at(chan); default: return false; } } virtual bool check_radio_config() { return true; }; //! There is always only one time core per radio time_core_3000::sptr _time64; boost::mutex _mutex; private: /************************************************************************ * Peripherals ***********************************************************************/ //! Stores pointers to all streaming-related radio cores struct radio_perifs_t { timed_wb_iface::sptr ctrl; }; std::map<size_t, radio_perifs_t> _perifs; size_t _num_tx_channels; size_t _num_rx_channels; // Cached values double _tick_rate; std::map<size_t, std::string> _tx_antenna; std::map<size_t, std::string> _rx_antenna; std::map<size_t, double> _tx_freq; std::map<size_t, double> _rx_freq; std::map<size_t, double> _tx_gain; std::map<size_t, double> _rx_gain; std::map<size_t, double> _rx_bandwidth; std::vector<bool> _continuous_streaming; }; /* class radio_ctrl_impl */ }} /* namespace uhd::rfnoc */ #endif /* INCLUDED_LIBUHD_RFNOC_RADIO_CTRL_IMPL_HPP */ // vim: sw=4 et:
_______________________________________________ USRP-users mailing list USRP-users@lists.ettus.com http://lists.ettus.com/mailman/listinfo/usrp-users_lists.ettus.com