diff options
Diffstat (limited to 'host/lib/usrp')
-rw-r--r-- | host/lib/usrp/b200/b200_iface.hpp | 3 | ||||
-rw-r--r-- | host/lib/usrp/b200/b200_impl.cpp | 122 | ||||
-rw-r--r-- | host/lib/usrp/b200/b200_impl.hpp | 55 | ||||
-rw-r--r-- | host/lib/usrp/b200/b200_io_impl.cpp | 156 | ||||
-rw-r--r-- | host/lib/usrp/common/ad9361_ctrl.cpp | 23 | ||||
-rw-r--r-- | host/lib/usrp/common/ad9361_ctrl.hpp | 27 | ||||
-rw-r--r-- | host/lib/usrp/common/ad9361_driver/ad9361_device.cpp | 171 | ||||
-rw-r--r-- | host/lib/usrp/common/ad9361_driver/ad9361_device.h | 16 | ||||
-rw-r--r-- | host/lib/usrp/common/ad9361_driver/ad9361_gain_tables.h | 162 | ||||
-rw-r--r-- | host/lib/usrp/e300/e300_impl.cpp | 2 | ||||
-rw-r--r-- | host/lib/usrp/e300/e300_network.cpp | 8 | ||||
-rw-r--r-- | host/lib/usrp/e300/e300_remote_codec_ctrl.cpp | 40 | ||||
-rw-r--r-- | host/lib/usrp/e300/e300_remote_codec_ctrl.hpp | 6 | ||||
-rw-r--r-- | host/lib/usrp/multi_usrp.cpp | 71 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_impl.cpp | 50 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_io_impl.cpp | 52 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_regs.hpp | 140 |
17 files changed, 818 insertions, 286 deletions
diff --git a/host/lib/usrp/b200/b200_iface.hpp b/host/lib/usrp/b200/b200_iface.hpp index 83adfdd64..1821865d3 100644 --- a/host/lib/usrp/b200/b200_iface.hpp +++ b/host/lib/usrp/b200/b200_iface.hpp @@ -26,7 +26,10 @@ #include "ad9361_ctrl.hpp" const static boost::uint16_t B200_VENDOR_ID = 0x2500; +const static boost::uint16_t B200_VENDOR_NI_ID = 0x3923; const static boost::uint16_t B200_PRODUCT_ID = 0x0020; +const static boost::uint16_t B200_PRODUCT_NI_ID = 0x7813; +const static boost::uint16_t B210_PRODUCT_NI_ID = 0x7814; const static boost::uint16_t FX3_VID = 0x04b4; const static boost::uint16_t FX3_DEFAULT_PID = 0x00f3; const static boost::uint16_t FX3_REENUM_PID = 0x00f0; diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp index 13169a5ed..ada25ad59 100644 --- a/host/lib/usrp/b200/b200_impl.cpp +++ b/host/lib/usrp/b200/b200_impl.cpp @@ -90,14 +90,16 @@ static device_addrs_t b200_find(const device_addr_t &hint) if (hint_i.has_key("addr") || hint_i.has_key("resource")) return b200_addrs; } - boost::uint16_t vid, pid; + size_t found = 0; + std::vector<usb_device_handle::vid_pid_pair_t> vid_pid_pair_list;//vid pid pair search list for devices. if(hint.has_key("vid") && hint.has_key("pid") && hint.has_key("type") && hint["type"] == "b200") { - vid = uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("vid")); - pid = uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("pid")); + vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("vid")), + uhd::cast::hexstr_cast<boost::uint16_t>(hint.get("pid")))); } else { - vid = B200_VENDOR_ID; - pid = B200_PRODUCT_ID; + vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID, B200_PRODUCT_ID)); + vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID, B200_PRODUCT_NI_ID)); + vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID, B210_PRODUCT_NI_ID)); } // Important note: @@ -107,8 +109,9 @@ static device_addrs_t b200_find(const device_addr_t &hint) // This requirement is a courtesy of libusb1.0 on windows. //find the usrps and load firmware - size_t found = 0; - BOOST_FOREACH(usb_device_handle::sptr handle, usb_device_handle::get_device_list(vid, pid)) { + std::vector<usb_device_handle::sptr> uhd_usb_device_vector = usb_device_handle::get_device_list(vid_pid_pair_list); + + BOOST_FOREACH(usb_device_handle::sptr handle, uhd_usb_device_vector) { //extract the firmware path for the b200 std::string b200_fw_image; try{ @@ -139,7 +142,7 @@ static device_addrs_t b200_find(const device_addr_t &hint) //search for the device until found or timeout while (boost::get_system_time() < timeout_time and b200_addrs.empty() and found != 0) { - BOOST_FOREACH(usb_device_handle::sptr handle, usb_device_handle::get_device_list(vid, pid)) + BOOST_FOREACH(usb_device_handle::sptr handle, usb_device_handle::get_device_list(vid_pid_pair_list)) { usb_control::sptr control; try{control = usb_control::make(handle, 0);} @@ -156,12 +159,16 @@ static device_addrs_t b200_find(const device_addr_t &hint) { switch (boost::lexical_cast<boost::uint16_t>(mb_eeprom["product"])) { + //0x0001 and 0x7737 are Ettus B200 product Ids. case 0x0001: case 0x7737: + case B200_PRODUCT_NI_ID: new_addr["product"] = "B200"; break; - case 0x7738: + //0x0002 and 0x7738 are Ettus B210 product Ids. case 0x0002: + case 0x7738: + case B210_PRODUCT_NI_ID: new_addr["product"] = "B210"; break; default: UHD_MSG(error) << "B200 unknown product code: " << mb_eeprom["product"] << std::endl; @@ -205,13 +212,50 @@ b200_impl::b200_impl(const device_addr_t &device_addr) //try to match the given device address with something on the USB bus boost::uint16_t vid = B200_VENDOR_ID; boost::uint16_t pid = B200_PRODUCT_ID; + bool specified_vid = false; + bool specified_pid = false; + if (device_addr.has_key("vid")) + { vid = uhd::cast::hexstr_cast<boost::uint16_t>(device_addr.get("vid")); + specified_vid = true; + } + if (device_addr.has_key("pid")) + { pid = uhd::cast::hexstr_cast<boost::uint16_t>(device_addr.get("pid")); + specified_pid = true; + } - std::vector<usb_device_handle::sptr> device_list = - usb_device_handle::get_device_list(vid, pid); + std::vector<usb_device_handle::vid_pid_pair_t> vid_pid_pair_list;//search list for devices. + + // Search only for specified VID and PID if both specified + if (specified_vid && specified_pid) + { + vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid,pid)); + } + // Search for all supported PIDs limited to specified VID if only VID specified + else if (specified_vid) + { + vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid,B200_PRODUCT_ID)); + vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid,B200_PRODUCT_NI_ID)); + vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid,B210_PRODUCT_NI_ID)); + } + // Search for all supported VIDs limited to specified PID if only PID specified + else if (specified_pid) + { + vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID,pid)); + vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID,pid)); + } + // Search for all supported devices if neither VID nor PID specified + else + { + vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID,B200_PRODUCT_ID)); + vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID,B200_PRODUCT_NI_ID)); + vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID,B210_PRODUCT_NI_ID)); + } + + std::vector<usb_device_handle::sptr> device_list = usb_device_handle::get_device_list(vid_pid_pair_list); //locate the matching handle in the device list usb_device_handle::sptr handle; @@ -245,13 +289,17 @@ b200_impl::b200_impl(const device_addr_t &device_addr) { switch (boost::lexical_cast<boost::uint16_t>(mb_eeprom["product"])) { + //0x0001 and 0x7737 are Ettus B200 product Ids. case 0x0001: case 0x7737: + case B200_PRODUCT_NI_ID: product_name = "B200"; default_file_name = B200_FPGA_FILE_NAME; break; - case 0x7738: + //0x0002 and 0x7738 are Ettus B210 product Ids. case 0x0002: + case 0x7738: + case B210_PRODUCT_NI_ID: product_name = "B210"; default_file_name = B210_FPGA_FILE_NAME; break; @@ -417,6 +465,7 @@ b200_impl::b200_impl(const device_addr_t &device_addr) .publish(boost::bind(&b200_impl::get_tick_rate, this)) .subscribe(boost::bind(&b200_impl::update_tick_rate, this, _1)); _tree->create<time_spec_t>(mb_path / "time" / "cmd"); + _tree->create<bool>(mb_path / "auto_tick_rate").set(false); //////////////////////////////////////////////////////////////////// // and do the misc mboard sensors @@ -517,6 +566,11 @@ b200_impl::b200_impl(const device_addr_t &device_addr) _tree->access<double>(mb_path / "rx_dsps" / str(boost::format("%u") % i)/ "rate/value").set(B200_DEFAULT_RATE); _tree->access<double>(mb_path / "tx_dsps" / str(boost::format("%u") % i) / "rate/value").set(B200_DEFAULT_RATE); } + // We can automatically choose a master clock rate, but not if the user specifies one + _tree->access<bool>(mb_path / "auto_tick_rate").set(not device_addr.has_key("master_clock_rate")); + if (not device_addr.has_key("master_clock_rate")) { + UHD_MSG(status) << "Setting master clock rate selection to 'automatic'." << std::endl; + } //GPS installed: use external ref, time, and init time spec if (_gps and _gps->gps_detected()) @@ -537,7 +591,7 @@ b200_impl::b200_impl(const device_addr_t &device_addr) b200_impl::~b200_impl(void) { - UHD_SAFE_CALL + UHD_SAFE_CALL ( _async_task.reset(); ) @@ -580,7 +634,7 @@ void b200_impl::setup_radio(const size_t dspno) _tree->create<meta_range_t>(rx_dsp_path / "rate" / "range") .publish(boost::bind(&rx_dsp_core_3000::get_host_rates, perif.ddc)); _tree->create<double>(rx_dsp_path / "rate" / "value") - .coerce(boost::bind(&rx_dsp_core_3000::set_host_rate, perif.ddc, _1)) + .coerce(boost::bind(&b200_impl::coerce_rx_samp_rate, this, perif.ddc, dspno, _1)) .subscribe(boost::bind(&b200_impl::update_rx_samp_rate, this, dspno, _1)) .set(0.0); // Can only set this after tick rate is initialized. _tree->create<double>(rx_dsp_path / "freq" / "value") @@ -604,7 +658,7 @@ void b200_impl::setup_radio(const size_t dspno) _tree->create<meta_range_t>(tx_dsp_path / "rate" / "range") .publish(boost::bind(&tx_dsp_core_3000::get_host_rates, perif.duc)); _tree->create<double>(tx_dsp_path / "rate" / "value") - .coerce(boost::bind(&tx_dsp_core_3000::set_host_rate, perif.duc, _1)) + .coerce(boost::bind(&b200_impl::coerce_tx_samp_rate, this, perif.duc, dspno, _1)) .subscribe(boost::bind(&b200_impl::update_tx_samp_rate, this, dspno, _1)) .set(0.0); // Can only set this after tick rate is initialized. _tree->create<double>(tx_dsp_path / "freq" / "value") @@ -648,7 +702,7 @@ void b200_impl::setup_radio(const size_t dspno) _tree->create<bool>(rf_fe_path / "use_lo_offset").set(false); _tree->create<double>(rf_fe_path / "bandwidth" / "value") .coerce(boost::bind(&ad9361_ctrl::set_bw_filter, _codec_ctrl, key, _1)) - .set(40e6); + .set(56e6); _tree->create<meta_range_t>(rf_fe_path / "bandwidth" / "range") .publish(boost::bind(&ad9361_ctrl::get_bw_filter_range, key)); _tree->create<double>(rf_fe_path / "freq" / "value") @@ -657,8 +711,20 @@ void b200_impl::setup_radio(const size_t dspno) .set(B200_DEFAULT_FREQ); _tree->create<meta_range_t>(rf_fe_path / "freq" / "range") .publish(boost::bind(&ad9361_ctrl::get_rf_freq_range)); + _tree->create<sensor_value_t>(rf_fe_path / "sensors" / "temp") + .publish(boost::bind(&ad9361_ctrl::get_temperature, _codec_ctrl)); //setup RX related stuff + if(direction) + { + _tree->create<bool>(rf_fe_path / "dc_offset" / "enable" ) + .subscribe(boost::bind(&ad9361_ctrl::set_dc_offset_auto, _codec_ctrl, key, _1)).set(true); + + _tree->create<bool>(rf_fe_path / "iq_balance" / "enable" ) + .subscribe(boost::bind(&ad9361_ctrl::set_iq_balance_auto, _codec_ctrl, key, _1)).set(true); + } + + //setup antenna stuff if (key[0] == 'R') { static const std::vector<std::string> ants = boost::assign::list_of("TX/RX")("RX2"); @@ -724,7 +790,7 @@ void b200_impl::codec_loopback_self_test(wb_iface::sptr iface) /*********************************************************************** * Sample and tick rate comprehension below **********************************************************************/ -void b200_impl::enforce_tick_rate_limits(size_t chan_count, double tick_rate, const char* direction /*= NULL*/) +void b200_impl::enforce_tick_rate_limits(size_t chan_count, double tick_rate, const std::string &direction /*= ""*/) { const size_t max_chans = 2; if (chan_count > max_chans) @@ -732,7 +798,7 @@ void b200_impl::enforce_tick_rate_limits(size_t chan_count, double tick_rate, co throw uhd::value_error(boost::str( boost::format("cannot not setup %d %s channels (maximum is %d)") % chan_count - % (direction ? direction : "data") + % (direction.empty() ? "data" : direction) % max_chans )); } @@ -746,20 +812,26 @@ void b200_impl::enforce_tick_rate_limits(size_t chan_count, double tick_rate, co % (tick_rate/1e6) % (max_tick_rate/1e6) % chan_count - % (direction ? direction : "data") + % (direction.empty() ? "data" : direction) )); } } } -double b200_impl::set_tick_rate(const double rate) +double b200_impl::set_tick_rate(const double new_tick_rate) { - UHD_MSG(status) << (boost::format("Asking for clock rate %.6f MHz\n") % (rate/1e6)); - - check_tick_rate_with_current_streamers(rate); // Defined in b200_io_impl.cpp + UHD_MSG(status) << (boost::format("Asking for clock rate %.6f MHz... ") % (new_tick_rate/1e6)) << std::flush; + check_tick_rate_with_current_streamers(new_tick_rate); // Defined in b200_io_impl.cpp + + // Make sure the clock rate is actually changed before doing + // the full Monty of setting regs and loopback tests etc. + if (std::abs(new_tick_rate - _tick_rate) < 1.0) { + UHD_MSG(status) << "OK" << std::endl; + return _tick_rate; + } - _tick_rate = _codec_ctrl->set_clock_rate(rate); - UHD_MSG(status) << (boost::format("Actually got clock rate %.6f MHz\n") % (_tick_rate/1e6)); + _tick_rate = _codec_ctrl->set_clock_rate(new_tick_rate); + UHD_MSG(status) << std::endl << (boost::format("Actually got clock rate %.6f MHz.") % (_tick_rate/1e6)) << std::endl; //reset after clock rate change this->reset_codec_dcm(); diff --git a/host/lib/usrp/b200/b200_impl.hpp b/host/lib/usrp/b200/b200_impl.hpp index 396819f9a..64d7aa7d0 100644 --- a/host/lib/usrp/b200/b200_impl.hpp +++ b/host/lib/usrp/b200/b200_impl.hpp @@ -98,7 +98,13 @@ public: uhd::rx_streamer::sptr get_rx_stream(const uhd::stream_args_t &args); uhd::tx_streamer::sptr get_tx_stream(const uhd::stream_args_t &args); bool recv_async_msg(uhd::async_metadata_t &, double); - void check_streamer_args(const uhd::stream_args_t &args, double tick_rate, const char* direction = NULL); + + //! Check that the combination of stream args and tick rate are valid. + // + // Basically figures out the arguments for enforce_tick_rate_limits() + // and calls said method. If arguments are invalid, throws a + // uhd::value_error. + void check_streamer_args(const uhd::stream_args_t &args, double tick_rate, const std::string &direction = ""); private: //controllers @@ -191,11 +197,56 @@ private: double _tick_rate; double get_tick_rate(void){return _tick_rate;} double set_tick_rate(const double rate); + + /*! \brief Choose a tick rate (master clock rate) that works well for the given sampling rate. + * + * This function will try and choose a master clock rate automatically. + * See the function definition for details on the algorithm. + * + * The chosen tick rate is the largest multiple of two that is smaler + * than the max tick rate. + * The base rate is either given explicitly, or is the lcm() of the tx + * and rx sampling rates. In that case, it reads the rates directly + * from the property tree. It also tries to guess the number of channels + * (for the max possible tick rate) by checking the available streamers. + * This value, too, can explicitly be given. + * + * \param rate If this is given, it will be used as a minimum rate, or + * argument to lcm(). + * \param tree_dsp_path The sampling rate from this property tree path + * will be ignored. + * \param num_chans If given, specifies the number of channels. + */ + void set_auto_tick_rate( + const double rate=0, + const uhd::fs_path &tree_dsp_path="", + size_t num_chans=0 + ); + void update_tick_rate(const double); - void enforce_tick_rate_limits(size_t chan_count, double tick_rate, const char* direction = NULL); + + /*! Check if \p tick_rate works with \p chan_count channels. + * + * Throws a uhd::value_error if not. + */ + void enforce_tick_rate_limits(size_t chan_count, double tick_rate, const std::string &direction = ""); void check_tick_rate_with_current_streamers(double rate); + /*! Return the max number of channels on active rx_streamer or tx_streamer objects associated with this device. + * + * \param direction Set to "TX" to only check tx_streamers, "RX" to only check + * rx_streamers. Any other value will check if \e any active + * streamers are available. + * \return Return the number of tx streamers (direction=="TX"), the number of rx + * streamers (direction=="RX") or the total number of streamers. + */ + size_t max_chan_count(const std::string &direction=""); + + //! Coercer, attached to the "rate/value" property on the rx dsps. + double coerce_rx_samp_rate(rx_dsp_core_3000::sptr, size_t, const double); void update_rx_samp_rate(const size_t, const double); + //! Coercer, attached to the "rate/value" property on the tx dsps. + double coerce_tx_samp_rate(tx_dsp_core_3000::sptr, size_t, const double); void update_tx_samp_rate(const size_t, const double); }; diff --git a/host/lib/usrp/b200/b200_io_impl.cpp b/host/lib/usrp/b200/b200_io_impl.cpp index 262c95f0d..60b925517 100644 --- a/host/lib/usrp/b200/b200_io_impl.cpp +++ b/host/lib/usrp/b200/b200_io_impl.cpp @@ -1,5 +1,5 @@ // -// Copyright 2012-2013 Ettus Research LLC +// Copyright 2012-2014 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 @@ -21,8 +21,10 @@ #include "../../transport/super_recv_packet_handler.hpp" #include "../../transport/super_send_packet_handler.hpp" #include "async_packet_handler.hpp" +#include <uhd/utils/math.hpp> #include <boost/bind.hpp> #include <boost/make_shared.hpp> +#include <boost/math/common_factor.hpp> #include <set> using namespace uhd; @@ -34,30 +36,32 @@ using namespace uhd::transport; **********************************************************************/ void b200_impl::check_tick_rate_with_current_streamers(double rate) { - size_t max_tx_chan_count = 0, max_rx_chan_count = 0; + // Defined in b200_impl.cpp + enforce_tick_rate_limits(max_chan_count("RX"), rate, "RX"); + enforce_tick_rate_limits(max_chan_count("TX"), rate, "TX"); +} + +// direction can either be "TX", "RX", or empty (default) +size_t b200_impl::max_chan_count(const std::string &direction /* = "" */) +{ + size_t max_count = 0; BOOST_FOREACH(radio_perifs_t &perif, _radio_perifs) { - { + if ((direction == "RX" or direction.empty()) and not perif.rx_streamer.expired()) { boost::shared_ptr<sph::recv_packet_streamer> rx_streamer = boost::dynamic_pointer_cast<sph::recv_packet_streamer>(perif.rx_streamer.lock()); - if (rx_streamer) - max_rx_chan_count = std::max(max_rx_chan_count, rx_streamer->get_num_channels()); + max_count = std::max(max_count, rx_streamer->get_num_channels()); } - - { + if ((direction == "TX" or direction.empty()) and not perif.tx_streamer.expired()) { boost::shared_ptr<sph::send_packet_streamer> tx_streamer = boost::dynamic_pointer_cast<sph::send_packet_streamer>(perif.tx_streamer.lock()); - if (tx_streamer) - max_tx_chan_count = std::max(max_tx_chan_count, tx_streamer->get_num_channels()); + max_count = std::max(max_count, tx_streamer->get_num_channels()); } } - - // Defined in b200_impl.cpp - enforce_tick_rate_limits(max_rx_chan_count, rate, "RX"); - enforce_tick_rate_limits(max_tx_chan_count, rate, "TX"); + return max_count; } -void b200_impl::check_streamer_args(const uhd::stream_args_t &args, double tick_rate, const char* direction /*= NULL*/) +void b200_impl::check_streamer_args(const uhd::stream_args_t &args, double tick_rate, const std::string &direction /*= ""*/) { std::set<size_t> chans_set; for (size_t stream_i = 0; stream_i < args.channels.size(); stream_i++) @@ -69,26 +73,120 @@ void b200_impl::check_streamer_args(const uhd::stream_args_t &args, double tick_ enforce_tick_rate_limits(chans_set.size(), tick_rate, direction); // Defined in b200_impl.cpp } -void b200_impl::update_tick_rate(const double rate) +void b200_impl::set_auto_tick_rate( + const double rate, + const fs_path &tree_dsp_path, + size_t num_chans +) { + if (num_chans == 0) { // Divine them + num_chans = std::max(size_t(1), max_chan_count()); + } + + // See also the doxygen documentation for these steps in b200_impl.hpp + // Step 1: Obtain LCM and max rate from all relevant dsps + boost::uint32_t lcm_rate = (rate == 0) ? 1 : static_cast<boost::uint32_t>(floor(rate + 0.5)); + for (int i = 0; i < 2; i++) { // Loop through rx and tx + std::string dir = (i == 0) ? "tx" : "rx"; + // We have no way of knowing which DSPs are used, so we check them all. + BOOST_FOREACH(const std::string &dsp_no, _tree->list(str(boost::format("/mboards/0/%s_dsps") % dir))) { + fs_path dsp_path = str(boost::format("/mboards/0/%s_dsps/%s") % dir % dsp_no); + if (dsp_path == tree_dsp_path) { + continue; + } + double this_dsp_rate = _tree->access<double>(dsp_path / "rate/value").get(); + // If this_dsp_rate == B200_DEFAULT_RATE, we assume the user did not actually set + // the sampling rate. If the user *did* set the rate to + // B200_DEFAULT_RATE on all DSPs, then this will still work (see below). + // If the user set one DSP to B200_DEFAULT_RATE and the other to + // a different rate, this also works if the rates are integer multiples + // of one another. Only for certain configurations of B200_DEFAULT_RATE + // and another rate that is not an integer multiple, this will be problematic. + // Since this case is less common than the case where a rate is left unset, + // we don't handle that but rather explain that corner case in the documentation. + if (this_dsp_rate == B200_DEFAULT_RATE) { + continue; + } + lcm_rate = boost::math::lcm<boost::uint32_t>( + lcm_rate, + static_cast<boost::uint32_t>(floor(this_dsp_rate + 0.5)) + ); + } + } + if (lcm_rate == 1) { + lcm_rate = static_cast<boost::uint32_t>(B200_DEFAULT_RATE); + } + + // Step 2: Determine whether if we can use lcm_rate (preferred), + // or have to give up because too large: + const double max_tick_rate = + ((num_chans <= 1) ? ad9361_device_t::AD9361_RECOMMENDED_MAX_CLOCK_RATE : ad9361_device_t::AD9361_MAX_CLOCK_RATE/2); + double base_rate = static_cast<double>(lcm_rate); + if (base_rate > max_tick_rate) { + UHD_MSG(warning) + << "Cannot automatically determine an appropriate tick rate for these sampling rates." << std::endl + << "Consider using different sampling rates, or manually specify a suitable master clock rate." << std::endl; + return; // Let the others handle this + } + + // Step 3: Choose the new rate + // Rules for choosing the tick rate: + // Choose a rate that is a power of 2 larger than the sampling rate, + // but at least 4. Cannot exceed the max tick rate, of course, but must + // be larger than the minimum tick rate. + // An equation that does all that is: + // + // f_auto = r * 2^floor(log2(f_max/r)) + // + // where r is the base rate and f_max is the maximum tick rate. The case + // where floor() yields 1 must be caught. + const double min_tick_rate = _codec_ctrl->get_clock_rate_range().start(); + // We use shifts here instead of 2^x because exp2() is not available in all compilers, + // also this guarantees no rounding issues. The type cast to int32_t serves as floor(): + boost::int32_t multiplier = (1 << boost::int32_t(uhd::math::log2(max_tick_rate / base_rate))); + if (multiplier == 2 and base_rate >= min_tick_rate) { + // Don't bother (see above) + multiplier = 1; + } + double new_rate = base_rate * multiplier; + UHD_ASSERT_THROW(new_rate >= min_tick_rate); + UHD_ASSERT_THROW(new_rate <= max_tick_rate); + + if (_tree->access<double>("/mboards/0/tick_rate").get() != new_rate) { + _tree->access<double>("/mboards/0/tick_rate").set(new_rate); + } +} + +void b200_impl::update_tick_rate(const double new_tick_rate) { - check_tick_rate_with_current_streamers(rate); + check_tick_rate_with_current_streamers(new_tick_rate); BOOST_FOREACH(radio_perifs_t &perif, _radio_perifs) { boost::shared_ptr<sph::recv_packet_streamer> my_streamer = boost::dynamic_pointer_cast<sph::recv_packet_streamer>(perif.rx_streamer.lock()); - if (my_streamer) my_streamer->set_tick_rate(rate); - perif.framer->set_tick_rate(_tick_rate); + if (my_streamer) my_streamer->set_tick_rate(new_tick_rate); + perif.framer->set_tick_rate(new_tick_rate); } BOOST_FOREACH(radio_perifs_t &perif, _radio_perifs) { boost::shared_ptr<sph::send_packet_streamer> my_streamer = boost::dynamic_pointer_cast<sph::send_packet_streamer>(perif.tx_streamer.lock()); - if (my_streamer) my_streamer->set_tick_rate(rate); - perif.deframer->set_tick_rate(_tick_rate); + if (my_streamer) my_streamer->set_tick_rate(new_tick_rate); + perif.deframer->set_tick_rate(new_tick_rate); } } + +double b200_impl::coerce_rx_samp_rate(rx_dsp_core_3000::sptr ddc, size_t dspno, const double rx_rate) +{ + // Have to set tick rate first, or the ddc will change the requested rate based on default tick rate + if (_tree->access<bool>("/mboards/0/auto_tick_rate").get()) { + const std::string dsp_path = (boost::format("/mboards/0/rx_dsps/%s") % dspno).str(); + set_auto_tick_rate(rx_rate, dsp_path); + } + return ddc->set_host_rate(rx_rate); +} + void b200_impl::update_rx_samp_rate(const size_t dspno, const double rate) { boost::shared_ptr<sph::recv_packet_streamer> my_streamer = @@ -99,6 +197,16 @@ void b200_impl::update_rx_samp_rate(const size_t dspno, const double rate) my_streamer->set_scale_factor(adj); } +double b200_impl::coerce_tx_samp_rate(tx_dsp_core_3000::sptr duc, size_t dspno, const double tx_rate) +{ + // Have to set tick rate first, or the duc will change the requested rate based on default tick rate + if (_tree->access<bool>("/mboards/0/auto_tick_rate").get()) { + const std::string dsp_path = (boost::format("/mboards/0/tx_dsps/%s") % dspno).str(); + set_auto_tick_rate(tx_rate, dsp_path); + } + return duc->set_host_rate(tx_rate); +} + void b200_impl::update_tx_samp_rate(const size_t dspno, const double rate) { boost::shared_ptr<sph::send_packet_streamer> my_streamer = @@ -264,6 +372,9 @@ rx_streamer::sptr b200_impl::get_rx_stream(const uhd::stream_args_t &args_) if (args.otw_format.empty()) args.otw_format = "sc16"; args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels; + if (_tree->access<bool>("/mboards/0/auto_tick_rate").get()) { + set_auto_tick_rate(0, "", args.channels.size()); + } check_streamer_args(args, this->get_tick_rate(), "RX"); boost::shared_ptr<sph::recv_packet_streamer> my_streamer; @@ -371,7 +482,10 @@ tx_streamer::sptr b200_impl::get_tx_stream(const uhd::stream_args_t &args_) if (args.otw_format.empty()) args.otw_format = "sc16"; args.channels = args.channels.empty()? std::vector<size_t>(1, 0) : args.channels; - check_streamer_args(args, this->get_tick_rate(), "TX"); + if (_tree->access<bool>("/mboards/0/auto_tick_rate").get()) { + set_auto_tick_rate(0, "", args.channels.size()); + } + check_streamer_args(args, this->get_tick_rate(), "RX"); boost::shared_ptr<sph::send_packet_streamer> my_streamer; for (size_t stream_i = 0; stream_i < args.channels.size(); stream_i++) diff --git a/host/lib/usrp/common/ad9361_ctrl.cpp b/host/lib/usrp/common/ad9361_ctrl.cpp index 85510530d..ada74cda5 100644 --- a/host/lib/usrp/common/ad9361_ctrl.cpp +++ b/host/lib/usrp/common/ad9361_ctrl.cpp @@ -16,7 +16,6 @@ // #include "ad9361_ctrl.hpp" -#include <uhd/exception.hpp> #include <uhd/types/ranges.hpp> #include <uhd/utils/msg.hpp> #include <uhd/types/serial.hpp> @@ -172,6 +171,28 @@ public: return sensor_value_t("RSSI", _device.get_rssi(chain), "dB"); } + //! read the internal temp sensor. Average over 3 results + sensor_value_t get_temperature() + { + return sensor_value_t("temp", _device.get_average_temperature(), "C"); + } + + void set_dc_offset_auto(const std::string &which, const bool on) + { + boost::lock_guard<boost::mutex> lock(_mutex); + + ad9361_device_t::direction_t direction = _get_direction_from_antenna(which); + _device.set_dc_offset_auto(direction,on); + } + + void set_iq_balance_auto(const std::string &which, const bool on) + { + boost::lock_guard<boost::mutex> lock(_mutex); + + ad9361_device_t::direction_t direction = _get_direction_from_antenna(which); + _device.set_iq_balance_auto(direction,on); + } + private: static ad9361_device_t::direction_t _get_direction_from_antenna(const std::string& antenna) { diff --git a/host/lib/usrp/common/ad9361_ctrl.hpp b/host/lib/usrp/common/ad9361_ctrl.hpp index c5718302f..5396de225 100644 --- a/host/lib/usrp/common/ad9361_ctrl.hpp +++ b/host/lib/usrp/common/ad9361_ctrl.hpp @@ -22,9 +22,11 @@ #include <uhd/types/ranges.hpp> #include <uhd/types/serial.hpp> #include <uhd/types/sensors.hpp> +#include <uhd/exception.hpp> #include <boost/shared_ptr.hpp> #include <ad9361_device.h> #include <string> +#include <complex> namespace uhd { namespace usrp { @@ -95,11 +97,34 @@ public: //! tune the given frontend, return the exact value virtual double tune(const std::string &which, const double value) = 0; - //! turn on/off data port loopback + //! set the DC offset for I and Q manually + void set_dc_offset(const std::string &, const std::complex<double>) + { + //This feature should not be used according to Analog Devices + throw uhd::runtime_error("ad9361_ctrl::set_dc_offset this feature is not supported on this device."); + } + + //! enable or disable the BB/RF DC tracking feature + virtual void set_dc_offset_auto(const std::string &which, const bool on) = 0; + + //! set the IQ correction value manually + void set_iq_balance(const std::string &, const std::complex<double>) + { + //This feature should not be used according to Analog Devices + throw uhd::runtime_error("ad9361_ctrl::set_iq_balance this feature is not supported on this device."); + } + + //! enable or disable the quadrature calibration + virtual void set_iq_balance_auto(const std::string &which, const bool on) = 0; + + //! turn on/off Catalina's data port loopback virtual void data_port_loopback(const bool on) = 0; //! read internal RSSI sensor virtual sensor_value_t get_rssi(const std::string &which) = 0; + + //! read the internal temp sensor + virtual sensor_value_t get_temperature() = 0; }; }} diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp b/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp index 7268aff2d..e5938184c 100644 --- a/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp +++ b/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp @@ -11,6 +11,7 @@ #include <cmath> #include <uhd/exception.hpp> #include <uhd/utils/log.hpp> +#include <uhd/utils/msg.hpp> #include <boost/cstdint.hpp> #include <boost/date_time/posix_time/posix_time.hpp> #include <boost/thread/thread.hpp> @@ -650,11 +651,12 @@ void ad9361_device_t::_setup_adc() } /* Calibrate the baseband DC offset. - * - * Note that this function is called from within the TX quadrature - * calibration function! */ + * Disables tracking + */ void ad9361_device_t::_calibrate_baseband_dc_offset() { + _io_iface->poke8(0x18b, 0x83); //Reset RF DC tracking flag + _io_iface->poke8(0x193, 0x3f); // Calibration settings _io_iface->poke8(0x190, 0x0f); // Set tracking coefficient //write_ad9361_reg(device, 0x190, /*0x0f*//*0xDF*/0x80*1 | 0x40*1 | (16+8/*+4*/)); // Set tracking coefficient: don't *4 counter, do decim /4, increased gain shift @@ -674,9 +676,8 @@ void ad9361_device_t::_calibrate_baseband_dc_offset() } /* Calibrate the RF DC offset. - * - * Note that this function is called from within the TX quadrature - * calibration function. */ + * Disables tracking + */ void ad9361_device_t::_calibrate_rf_dc_offset() { /* Some settings are frequency-dependent. */ @@ -691,7 +692,7 @@ void ad9361_device_t::_calibrate_rf_dc_offset() } _io_iface->poke8(0x185, 0x20); // RF DC Offset wait count - _io_iface->poke8(0x18b, 0x83); + _io_iface->poke8(0x18b, 0x83); // Disable tracking _io_iface->poke8(0x189, 0x30); /* Run the calibration! */ @@ -707,6 +708,16 @@ void ad9361_device_t::_calibrate_rf_dc_offset() } } +void ad9361_device_t::_configure_bb_rf_dc_tracking(const bool on) +{ + if(on) + { + _io_iface->poke8(0x18b, 0xad); // Enable BB and RF DC tracking + } else { + _io_iface->poke8(0x18b, 0x83); // Disable BB and RF DC tracking + } +} + /* Start the RX quadrature calibration. * * Note that we are using AD9361's 'tracking' feature for RX quadrature @@ -719,16 +730,20 @@ void ad9361_device_t::_calibrate_rx_quadrature() _io_iface->poke8(0x16e, 0x25); // RX Gain index to use for cal _io_iface->poke8(0x16a, 0x75); // Set Kexp phase _io_iface->poke8(0x16b, 0x15); // Set Kexp amplitude - _io_iface->poke8(0x169, 0xcf); // Continuous tracking mode - _io_iface->poke8(0x18b, 0xad); + + if(_use_iq_balance_correction) + { + _io_iface->poke8(0x169, 0xcf); // Continuous tracking mode. Gets disabled in _tx_quadrature_cal_routine! + } } -/* TX quadtrature calibration routine. +/* TX quadrature calibration routine. * * The TX quadrature needs to be done twice, once for each TX chain, with * only one register change in between. Thus, this function enacts the * calibrations, and it is called from calibrate_tx_quadrature. */ void ad9361_device_t::_tx_quadrature_cal_routine() { + /* This is a weird process, but here is how it works: * 1) Read the calibrated NCO frequency bits out of 0A3. * 2) Write the two bits to the RX NCO freq part of 0A0. @@ -773,12 +788,6 @@ void ad9361_device_t::_tx_quadrature_cal_routine() { _io_iface->poke8(0x0a4, 0xf0); // Cal setting conut _io_iface->poke8(0x0ae, 0x00); // Cal LPF gain index (split mode) - /* First, calibrate the baseband DC offset. */ - _calibrate_baseband_dc_offset(); - - /* Second, calibrate the RF DC offset. */ - _calibrate_rf_dc_offset(); - /* Now, calibrate the TX quadrature! */ size_t count = 0; _io_iface->poke8(0x016, 0x10); @@ -793,9 +802,7 @@ void ad9361_device_t::_tx_quadrature_cal_routine() { } /* Run the TX quadrature calibration. - * - * Note that from within this function we are also triggering the baseband - * and RF DC calibrations. */ + */ void ad9361_device_t::_calibrate_tx_quadrature() { /* Make sure we are, in fact, in the ALERT state. If not, something is @@ -879,7 +886,7 @@ void ad9361_device_t::_program_mixer_gm_subtable() void ad9361_device_t::_program_gain_table() { /* Figure out which gain table we should be using for our current * frequency band. */ - boost::uint8_t (*gain_table)[5] = NULL; + boost::uint8_t (*gain_table)[3] = NULL; boost::uint8_t new_gain_table; if (_rx_freq < 1300e6) { gain_table = gain_table_sub_1300mhz; @@ -910,9 +917,9 @@ void ad9361_device_t::_program_gain_table() { boost::uint8_t index = 0; for (; index < 77; index++) { _io_iface->poke8(0x130, index); - _io_iface->poke8(0x131, gain_table[index][1]); - _io_iface->poke8(0x132, gain_table[index][2]); - _io_iface->poke8(0x133, gain_table[index][3]); + _io_iface->poke8(0x131, gain_table[index][0]); + _io_iface->poke8(0x132, gain_table[index][1]); + _io_iface->poke8(0x133, gain_table[index][2]); _io_iface->poke8(0x137, 0x1E); _io_iface->poke8(0x134, 0x00); _io_iface->poke8(0x134, 0x00); @@ -1256,6 +1263,7 @@ double ad9361_device_t::_setup_rates(const double rate) int divfactor = 0; _tfir_factor = 0; _rfir_factor = 0; + if (rate < 0.33e6) { // RX1 + RX2 enabled, 3, 2, 2, 4 _regs.rxfilt = B8(11101111); @@ -1411,6 +1419,8 @@ void ad9361_device_t::initialize() _rx2_gain = 0; _tx1_gain = 0; _tx2_gain = 0; + _use_dc_offset_correction = true; + _use_iq_balance_correction = true; /* Reset the device. */ _io_iface->poke8(0x000, 0x01); @@ -1500,7 +1510,7 @@ void ad9361_device_t::initialize() /* Setup AuxADC */ _io_iface->poke8(0x00B, 0x00); // Temp Sensor Setup (Offset) _io_iface->poke8(0x00C, 0x00); // Temp Sensor Setup (Temp Window) - _io_iface->poke8(0x00D, 0x03); // Temp Sensor Setup (Periodic Measure) + _io_iface->poke8(0x00D, 0x00); // Temp Sensor Setup (Manual Measure) _io_iface->poke8(0x00F, 0x04); // Temp Sensor Setup (Decimation) _io_iface->poke8(0x01C, 0x10); // AuxADC Setup (Clock Div) _io_iface->poke8(0x01D, 0x01); // AuxADC Setup (Decimation/Enable) @@ -1563,8 +1573,11 @@ void ad9361_device_t::initialize() _setup_adc(); + _calibrate_baseband_dc_offset(); + _calibrate_rf_dc_offset(); _calibrate_tx_quadrature(); _calibrate_rx_quadrature(); + _configure_bb_rf_dc_tracking(_use_dc_offset_correction); // cals done, set PPORT config switch (_client_params->get_digital_interface_mode()) { @@ -1687,8 +1700,11 @@ double ad9361_device_t::set_clock_rate(const double req_rate) _setup_adc(); + _calibrate_baseband_dc_offset(); + _calibrate_rf_dc_offset(); _calibrate_tx_quadrature(); _calibrate_rx_quadrature(); + _configure_bb_rf_dc_tracking(_use_dc_offset_correction); // cals done, set PPORT config switch (_client_params->get_digital_interface_mode()) { @@ -1841,9 +1857,11 @@ double ad9361_device_t::tune(direction_t direction, const double value) _reprogram_gains(); /* Run the calibration algorithms. */ + _calibrate_baseband_dc_offset(); + _calibrate_rf_dc_offset(); _calibrate_tx_quadrature(); _calibrate_rx_quadrature(); - + _configure_bb_rf_dc_tracking(_use_dc_offset_correction); //if this is not done here, bb dc offset is not good /* If we were in the FDD state, return it now. */ if (not_in_alert) { _io_iface->poke8(0x014, 0x21); @@ -1946,4 +1964,107 @@ double ad9361_device_t::get_rssi(chain_t chain) return rssi; } +/* + * Returns the reading of the internal temperature sensor. + * One point calibration of the sensor was done according to datasheet + * leading to the given default constant correction factor. + */ +double ad9361_device_t::_get_temperature(const double cal_offset, const double timeout) +{ + //set 0x01D[0] to 1 to disable AuxADC GPIO reading + boost::uint8_t tmp = 0; + tmp = _io_iface->peek8(0x01D); + _io_iface->poke8(0x01D, (tmp | 0x01)); + _io_iface->poke8(0x00B, 0); //set offset to 0 + + _io_iface->poke8(0x00C, 0x01); //start reading, clears bit 0x00C[1] + boost::posix_time::ptime start_time = boost::posix_time::microsec_clock::local_time(); + boost::posix_time::time_duration elapsed; + //wait for valid data (toggle of bit 1 in 0x00C) + while(((_io_iface->peek8(0x00C) >> 1) & 0x01) == 0) { + boost::this_thread::sleep(boost::posix_time::microseconds(100)); + elapsed = boost::posix_time::microsec_clock::local_time() - start_time; + if(elapsed.total_milliseconds() > (timeout*1000)) + { + throw uhd::runtime_error("[ad9361_device_t] timeout while reading temperature"); + } + } + _io_iface->poke8(0x00C, 0x00); //clear read flag + + boost::uint8_t temp = _io_iface->peek8(0x00E); //read temperature. + double tmp_temp = temp/1.140f; //according to ADI driver + tmp_temp = tmp_temp + cal_offset; //Constant offset acquired by one point calibration. + + return tmp_temp; +} + +double ad9361_device_t::get_average_temperature(const double cal_offset, const size_t num_samples) +{ + double d_temp = 0; + for(size_t i = 0; i < num_samples; i++) { + double tmp_temp = _get_temperature(cal_offset); + d_temp += (tmp_temp/num_samples); + } + return d_temp; +} + +void ad9361_device_t::set_dc_offset_auto(direction_t direction, const bool on) +{ + if(direction == RX) + { + _use_dc_offset_correction = on; + _configure_bb_rf_dc_tracking(_use_dc_offset_correction); + if(on) + { + _io_iface->poke8(0x182, (_io_iface->peek8(0x182) & (~((1 << 7) | (1 << 6) | (1 << 3) | (1 << 2))))); //Clear force bits + //Do a single shot DC offset cal before enabling tracking (Not possible if not in ALERT state. Is it necessary?) + } else { + //clear current config values + _io_iface->poke8(0x182, (_io_iface->peek8(0x182) | ((1 << 7) | (1 << 6) | (1 << 3) | (1 << 2)))); //Set input A and input B&C force enable bits + _io_iface->poke8(0x174, 0x00); + _io_iface->poke8(0x175, 0x00); + _io_iface->poke8(0x176, 0x00); + _io_iface->poke8(0x177, 0x00); + _io_iface->poke8(0x178, 0x00); + _io_iface->poke8(0x17D, 0x00); + _io_iface->poke8(0x17E, 0x00); + _io_iface->poke8(0x17F, 0x00); + _io_iface->poke8(0x180, 0x00); + _io_iface->poke8(0x181, 0x00); + } + } else { + // DC offset is removed during TX quad cal + throw uhd::runtime_error("[ad9361_device_t] [set_iq_balance_auto] INVALID_CODE_PATH"); + } +} + +void ad9361_device_t::set_iq_balance_auto(direction_t direction, const bool on) +{ + if(direction == RX) + { + _use_iq_balance_correction = on; + if(on) + { + //disable force registers and enable tracking + _io_iface->poke8(0x182, (_io_iface->peek8(0x182) & (~ ( (1<<1) | (1<<0) | (1<<5) | (1<<4) )))); + _calibrate_rx_quadrature(); + } else { + //disable IQ tracking + _io_iface->poke8(0x169, 0xc0); + //clear current config values + _io_iface->poke8(0x182, (_io_iface->peek8(0x182) | ((1 << 1) | (1 << 0) | (1 << 5) | (1 << 4)))); //Set Rx2 input B&C force enable bit + _io_iface->poke8(0x17B, 0x00); + _io_iface->poke8(0x17C, 0x00); + _io_iface->poke8(0x179, 0x00); + _io_iface->poke8(0x17A, 0x00); + _io_iface->poke8(0x170, 0x00); + _io_iface->poke8(0x171, 0x00); + _io_iface->poke8(0x172, 0x00); + _io_iface->poke8(0x173, 0x00); + } + } else { + throw uhd::runtime_error("[ad9361_device_t] [set_iq_balance_auto] INVALID_CODE_PATH"); + } +} + }} diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_device.h b/host/lib/usrp/common/ad9361_driver/ad9361_device.h index ca83f3037..93dc413d5 100644 --- a/host/lib/usrp/common/ad9361_driver/ad9361_device.h +++ b/host/lib/usrp/common/ad9361_driver/ad9361_device.h @@ -66,6 +66,18 @@ public: /* Read back the internal RSSI measurement data. */ double get_rssi(chain_t chain); + /*! Read the internal temperature sensor + *\param calibrate return raw sensor readings or apply calibration factor. + *\param num_samples number of measurements to average over + */ + double get_average_temperature(const double cal_offset = -30.0, const size_t num_samples = 3); + + /* Turn on/off AD9361's RX DC offset correction */ + void set_dc_offset_auto(direction_t direction, const bool on); + + /* Turn on/off AD9361's RX IQ imbalance correction */ + void set_iq_balance_auto(direction_t direction, const bool on); + //Constants static const double AD9361_MAX_GAIN; static const double AD9361_MAX_CLOCK_RATE; @@ -95,6 +107,8 @@ private: //Methods void _reprogram_gains(); double _tune_helper(direction_t direction, const double value); double _setup_rates(const double rate); + double _get_temperature(const double cal_offset, const double timeout = 0.1); + void _configure_bb_rf_dc_tracking(const bool on); private: //Members typedef struct { @@ -123,6 +137,8 @@ private: //Members chip_regs_t _regs; //Synchronization boost::recursive_mutex _mutex; + bool _use_dc_offset_correction; + bool _use_iq_balance_correction; }; }} //namespace diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_gain_tables.h b/host/lib/usrp/common/ad9361_driver/ad9361_gain_tables.h index 786029d6e..553655fa5 100644 --- a/host/lib/usrp/common/ad9361_driver/ad9361_gain_tables.h +++ b/host/lib/usrp/common/ad9361_driver/ad9361_gain_tables.h @@ -7,91 +7,91 @@ #include <boost/cstdint.hpp> -boost::uint8_t gain_table_sub_1300mhz[77][5] = { {0,0x00,0x00,0x20,1}, - {1,0x00,0x00,0x00,0}, {2,0x00,0x00,0x00,0}, {3,0x00,0x01,0x00,0}, - {4,0x00,0x02,0x00,0}, {5,0x00,0x03,0x00,0}, {6,0x00,0x04,0x00,0}, - {7,0x00,0x05,0x00,0}, {8,0x01,0x03,0x20,1}, {9,0x01,0x04,0x00,0}, - {10,0x01,0x05,0x00,0}, {11,0x01,0x06,0x00,0}, {12,0x01,0x07,0x00,0}, - {13,0x01,0x08,0x00,0}, {14,0x01,0x09,0x00,0}, {15,0x01,0x0A,0x00,0}, - {16,0x01,0x0B,0x00,0}, {17,0x01,0x0C,0x00,0}, {18,0x01,0x0D,0x00,0}, - {19,0x01,0x0E,0x00,0}, {20,0x02,0x09,0x20,1}, {21,0x02,0x0A,0x00,0}, - {22,0x02,0x0B,0x00,0}, {23,0x02,0x0C,0x00,0}, {24,0x02,0x0D,0x00,0}, - {25,0x02,0x0E,0x00,0}, {26,0x02,0x0F,0x00,0}, {27,0x02,0x10,0x00,0}, - {28,0x02,0x2B,0x20,1}, {29,0x02,0x2C,0x00,0}, {30,0x04,0x27,0x20,1}, - {31,0x04,0x28,0x00,0}, {32,0x04,0x29,0x00,0}, {33,0x04,0x2A,0x00,0}, - {34,0x04,0x2B,0x00,1}, {35,0x24,0x21,0x20,0}, {36,0x24,0x22,0x00,1}, - {37,0x44,0x20,0x20,0}, {38,0x44,0x21,0x00,0}, {39,0x44,0x22,0x00,0}, - {40,0x44,0x23,0x00,0}, {41,0x44,0x24,0x00,0}, {42,0x44,0x25,0x00,0}, - {43,0x44,0x26,0x00,0}, {44,0x44,0x27,0x00,0}, {45,0x44,0x28,0x00,0}, - {46,0x44,0x29,0x00,0}, {47,0x44,0x2A,0x00,0}, {48,0x44,0x2B,0x00,0}, - {49,0x44,0x2C,0x00,0}, {50,0x44,0x2D,0x00,0}, {51,0x44,0x2E,0x00,0}, - {52,0x44,0x2F,0x00,0}, {53,0x44,0x30,0x00,0}, {54,0x44,0x31,0x00,0}, - {55,0x64,0x2E,0x20,1}, {56,0x64,0x2F,0x00,0}, {57,0x64,0x30,0x00,0}, - {58,0x64,0x31,0x00,0}, {59,0x64,0x32,0x00,0}, {60,0x64,0x33,0x00,0}, - {61,0x64,0x34,0x00,0}, {62,0x64,0x35,0x00,0}, {63,0x64,0x36,0x00,0}, - {64,0x64,0x37,0x00,0}, {65,0x64,0x38,0x00,0}, {66,0x65,0x38,0x20,1}, - {67,0x66,0x38,0x20,1}, {68,0x67,0x38,0x20,1}, {69,0x68,0x38,0x20,1}, - {70,0x69,0x38,0x20,1}, {71,0x6A,0x38,0x20,1}, {72,0x6B,0x38,0x20,1}, - {73,0x6C,0x38,0x20,1}, {74,0x6D,0x38,0x20,1}, {75,0x6E,0x38,0x20,1}, - {76,0x6F,0x38,0x20,1}}; +boost::uint8_t gain_table_sub_1300mhz[77][3] = { +{ 0x00, 0x00, 0x20 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, +{ 0x00, 0x01, 0x00 }, { 0x00, 0x02, 0x00 }, { 0x00, 0x03, 0x00 }, +{ 0x00, 0x04, 0x00 }, { 0x00, 0x05, 0x00 }, { 0x01, 0x03, 0x20 }, +{ 0x01, 0x04, 0x00 }, { 0x01, 0x05, 0x00 }, { 0x01, 0x06, 0x00 }, +{ 0x01, 0x07, 0x00 }, { 0x01, 0x08, 0x00 }, { 0x01, 0x09, 0x00 }, +{ 0x01, 0x0A, 0x00 }, { 0x01, 0x0B, 0x00 }, { 0x01, 0x0C, 0x00 }, +{ 0x01, 0x0D, 0x00 }, { 0x01, 0x0E, 0x00 }, { 0x02, 0x09, 0x20 }, +{ 0x02, 0x0A, 0x00 }, { 0x02, 0x0B, 0x00 }, { 0x02, 0x0C, 0x00 }, +{ 0x02, 0x0D, 0x00 }, { 0x02, 0x0E, 0x00 }, { 0x02, 0x0F, 0x00 }, +{ 0x02, 0x10, 0x00 }, { 0x02, 0x2B, 0x20 }, { 0x02, 0x2C, 0x00 }, +{ 0x04, 0x28, 0x20 }, { 0x04, 0x29, 0x00 }, { 0x04, 0x2A, 0x00 }, +{ 0x04, 0x2B, 0x00 }, { 0x24, 0x20, 0x20 }, { 0x24, 0x21, 0x00 }, +{ 0x44, 0x20, 0x20 }, { 0x44, 0x21, 0x00 }, { 0x44, 0x22, 0x00 }, +{ 0x44, 0x23, 0x00 }, { 0x44, 0x24, 0x00 }, { 0x44, 0x25, 0x00 }, +{ 0x44, 0x26, 0x00 }, { 0x44, 0x27, 0x00 }, { 0x44, 0x28, 0x00 }, +{ 0x44, 0x29, 0x00 }, { 0x44, 0x2A, 0x00 }, { 0x44, 0x2B, 0x00 }, +{ 0x44, 0x2C, 0x00 }, { 0x44, 0x2D, 0x00 }, { 0x44, 0x2E, 0x00 }, +{ 0x44, 0x2F, 0x00 }, { 0x44, 0x30, 0x00 }, { 0x44, 0x31, 0x00 }, +{ 0x44, 0x32, 0x00 }, { 0x64, 0x2E, 0x20 }, { 0x64, 0x2F, 0x00 }, +{ 0x64, 0x30, 0x00 }, { 0x64, 0x31, 0x00 }, { 0x64, 0x32, 0x00 }, +{ 0x64, 0x33, 0x00 }, { 0x64, 0x34, 0x00 }, { 0x64, 0x35, 0x00 }, +{ 0x64, 0x36, 0x00 }, { 0x64, 0x37, 0x00 }, { 0x64, 0x38, 0x00 }, +{ 0x65, 0x38, 0x20 }, { 0x66, 0x38, 0x20 }, { 0x67, 0x38, 0x20 }, +{ 0x68, 0x38, 0x20 }, { 0x69, 0x38, 0x20 }, { 0x6A, 0x38, 0x20 }, +{ 0x6B, 0x38, 0x20 }, { 0x6C, 0x38, 0x20 }, { 0x6D, 0x38, 0x20 }, +{ 0x6E, 0x38, 0x20 }, { 0x6F, 0x38, 0x20 } }; -boost::uint8_t gain_table_1300mhz_to_4000mhz[77][5] = { {0,0x00,0x00,0x20,1}, - {1,0x00,0x00,0x00,0}, {2,0x00,0x00,0x00,0}, {3,0x00,0x01,0x00,0}, - {4,0x00,0x02,0x00,0}, {5,0x00,0x03,0x00,0}, {6,0x00,0x04,0x00,0}, - {7,0x00,0x05,0x00,0}, {8,0x01,0x03,0x20,1}, {9,0x01,0x04,0x00,0}, - {10,0x01,0x05,0x00,0}, {11,0x01,0x06,0x00,0}, {12,0x01,0x07,0x00,0}, - {13,0x01,0x08,0x00,0}, {14,0x01,0x09,0x00,0}, {15,0x01,0x0A,0x00,0}, - {16,0x01,0x0B,0x00,0}, {17,0x01,0x0C,0x00,0}, {18,0x01,0x0D,0x00,0}, - {19,0x01,0x0E,0x00,0}, {20,0x02,0x09,0x20,1}, {21,0x02,0x0A,0x00,0}, - {22,0x02,0x0B,0x00,0}, {23,0x02,0x0C,0x00,0}, {24,0x02,0x0D,0x00,0}, - {25,0x02,0x0E,0x00,0}, {26,0x02,0x0F,0x00,0}, {27,0x02,0x10,0x00,0}, - {28,0x02,0x2B,0x20,1}, {29,0x02,0x2C,0x00,0}, {30,0x04,0x28,0x20,1}, - {31,0x04,0x29,0x00,0}, {32,0x04,0x2A,0x00,0}, {33,0x04,0x2B,0x00,0}, - {34,0x24,0x20,0x20,0}, {35,0x24,0x21,0x00,1}, {36,0x44,0x20,0x20,0}, - {37,0x44,0x21,0x00,1}, {38,0x44,0x22,0x00,0}, {39,0x44,0x23,0x00,0}, - {40,0x44,0x24,0x00,0}, {41,0x44,0x25,0x00,0}, {42,0x44,0x26,0x00,0}, - {43,0x44,0x27,0x00,0}, {44,0x44,0x28,0x00,0}, {45,0x44,0x29,0x00,0}, - {46,0x44,0x2A,0x00,0}, {47,0x44,0x2B,0x00,0}, {48,0x44,0x2C,0x00,0}, - {49,0x44,0x2D,0x00,0}, {50,0x44,0x2E,0x00,0}, {51,0x44,0x2F,0x00,0}, - {52,0x44,0x30,0x00,0}, {53,0x44,0x31,0x00,0}, {54,0x44,0x32,0x00,0}, - {55,0x64,0x2E,0x20,1}, {56,0x64,0x2F,0x00,0}, {57,0x64,0x30,0x00,0}, - {58,0x64,0x31,0x00,0}, {59,0x64,0x32,0x00,0}, {60,0x64,0x33,0x00,0}, - {61,0x64,0x34,0x00,0}, {62,0x64,0x35,0x00,0}, {63,0x64,0x36,0x00,0}, - {64,0x64,0x37,0x00,0}, {65,0x64,0x38,0x00,0}, {66,0x65,0x38,0x20,1}, - {67,0x66,0x38,0x20,1}, {68,0x67,0x38,0x20,1}, {69,0x68,0x38,0x20,1}, - {70,0x69,0x38,0x20,1}, {71,0x6A,0x38,0x20,1}, {72,0x6B,0x38,0x20,1}, - {73,0x6C,0x38,0x20,1}, {74,0x6D,0x38,0x20,1}, {75,0x6E,0x38,0x20,1}, - {76,0x6F,0x38,0x20,1}}; +boost::uint8_t gain_table_1300mhz_to_4000mhz[77][3] = { +{ 0x00, 0x00, 0x20 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, +{ 0x00, 0x01, 0x00 }, { 0x00, 0x02, 0x00 }, { 0x00, 0x03, 0x00 }, +{ 0x00, 0x04, 0x00 }, { 0x00, 0x05, 0x00 }, { 0x01, 0x03, 0x20 }, +{ 0x01, 0x04, 0x00 }, { 0x01, 0x05, 0x00 }, { 0x01, 0x06, 0x00 }, +{ 0x01, 0x07, 0x00 }, { 0x01, 0x08, 0x00 }, { 0x01, 0x09, 0x00 }, +{ 0x01, 0x0A, 0x00 }, { 0x01, 0x0B, 0x00 }, { 0x01, 0x0C, 0x00 }, +{ 0x01, 0x0D, 0x00 }, { 0x01, 0x0E, 0x00 }, { 0x02, 0x09, 0x20 }, +{ 0x02, 0x0A, 0x00 }, { 0x02, 0x0B, 0x00 }, { 0x02, 0x0C, 0x00 }, +{ 0x02, 0x0D, 0x00 }, { 0x02, 0x0E, 0x00 }, { 0x02, 0x0F, 0x00 }, +{ 0x02, 0x10, 0x00 }, { 0x02, 0x2B, 0x20 }, { 0x02, 0x2C, 0x00 }, +{ 0x04, 0x27, 0x20 }, { 0x04, 0x28, 0x00 }, { 0x04, 0x29, 0x00 }, +{ 0x04, 0x2A, 0x00 }, { 0x04, 0x2B, 0x00 }, { 0x24, 0x21, 0x20 }, +{ 0x24, 0x22, 0x00 }, { 0x44, 0x20, 0x20 }, { 0x44, 0x21, 0x00 }, +{ 0x44, 0x22, 0x00 }, { 0x44, 0x23, 0x00 }, { 0x44, 0x24, 0x00 }, +{ 0x44, 0x25, 0x00 }, { 0x44, 0x26, 0x00 }, { 0x44, 0x27, 0x00 }, +{ 0x44, 0x28, 0x00 }, { 0x44, 0x29, 0x00 }, { 0x44, 0x2A, 0x00 }, +{ 0x44, 0x2B, 0x00 }, { 0x44, 0x2C, 0x00 }, { 0x44, 0x2D, 0x00 }, +{ 0x44, 0x2E, 0x00 }, { 0x44, 0x2F, 0x00 }, { 0x44, 0x30, 0x00 }, +{ 0x44, 0x31, 0x00 }, { 0x64, 0x2E, 0x20 }, { 0x64, 0x2F, 0x00 }, +{ 0x64, 0x30, 0x00 }, { 0x64, 0x31, 0x00 }, { 0x64, 0x32, 0x00 }, +{ 0x64, 0x33, 0x00 }, { 0x64, 0x34, 0x00 }, { 0x64, 0x35, 0x00 }, +{ 0x64, 0x36, 0x00 }, { 0x64, 0x37, 0x00 }, { 0x64, 0x38, 0x00 }, +{ 0x65, 0x38, 0x20 }, { 0x66, 0x38, 0x20 }, { 0x67, 0x38, 0x20 }, +{ 0x68, 0x38, 0x20 }, { 0x69, 0x38, 0x20 }, { 0x6A, 0x38, 0x20 }, +{ 0x6B, 0x38, 0x20 }, { 0x6C, 0x38, 0x20 }, { 0x6D, 0x38, 0x20 }, +{ 0x6E, 0x38, 0x20 }, { 0x6F, 0x38, 0x20 } }; -boost::uint8_t gain_table_4000mhz_to_6000mhz[77][5] = { {0,0x00,0x00,0x20,1}, - {1,0x00,0x00,0x00,0}, {2,0x00,0x00,0x00,0}, {3,0x00,0x00,0x00,0}, - {4,0x00,0x00,0x00,0}, {5,0x00,0x01,0x00,0}, {6,0x00,0x02,0x00,0}, - {7,0x00,0x03,0x00,0}, {8,0x01,0x01,0x20,1}, {9,0x01,0x02,0x00,0}, - {10,0x01,0x03,0x00,0}, {11,0x01,0x04,0x20,1}, {12,0x01,0x05,0x00,0}, - {13,0x01,0x06,0x00,0}, {14,0x01,0x07,0x00,0}, {15,0x01,0x08,0x00,0}, - {16,0x01,0x09,0x00,0}, {17,0x01,0x0A,0x00,0}, {18,0x01,0x0B,0x00,0}, - {19,0x01,0x0C,0x00,0}, {20,0x02,0x08,0x20,1}, {21,0x02,0x09,0x00,0}, - {22,0x02,0x0A,0x00,0}, {23,0x02,0x0B,0x20,1}, {24,0x02,0x0C,0x00,0}, - {25,0x02,0x0D,0x00,0}, {26,0x02,0x0E,0x00,0}, {27,0x02,0x0F,0x00,0}, - {28,0x02,0x2A,0x20,1}, {29,0x02,0x2B,0x00,0}, {30,0x04,0x27,0x20,1}, - {31,0x04,0x28,0x00,0}, {32,0x04,0x29,0x00,0}, {33,0x04,0x2A,0x00,0}, - {34,0x04,0x2B,0x00,0}, {35,0x04,0x2C,0x00,0}, {36,0x04,0x2D,0x00,0}, - {37,0x24,0x20,0x20,1}, {38,0x24,0x21,0x00,0}, {39,0x24,0x22,0x00,0}, - {40,0x44,0x20,0x20,1}, {41,0x44,0x21,0x00,0}, {42,0x44,0x22,0x00,0}, - {43,0x44,0x23,0x00,0}, {44,0x44,0x24,0x00,0}, {45,0x44,0x25,0x00,0}, - {46,0x44,0x26,0x00,0}, {47,0x44,0x27,0x00,0}, {48,0x44,0x28,0x00,0}, - {49,0x44,0x29,0x00,0}, {50,0x44,0x2A,0x00,0}, {51,0x44,0x2B,0x00,0}, - {52,0x44,0x2C,0x00,0}, {53,0x44,0x2D,0x00,0}, {54,0x44,0x2E,0x00,0}, - {55,0x64,0x2E,0x20,1}, {56,0x64,0x2F,0x00,0}, {57,0x64,0x30,0x00,0}, - {58,0x64,0x31,0x00,0}, {59,0x64,0x32,0x00,0}, {60,0x64,0x33,0x00,0}, - {61,0x64,0x34,0x00,0}, {62,0x64,0x35,0x00,0}, {63,0x64,0x36,0x00,0}, - {64,0x64,0x37,0x00,0}, {65,0x64,0x38,0x00,0}, {66,0x65,0x38,0x20,1}, - {67,0x66,0x38,0x20,1}, {68,0x67,0x38,0x20,1}, {69,0x68,0x38,0x20,1}, - {70,0x69,0x38,0x20,1}, {71,0x6A,0x38,0x20,1}, {72,0x6B,0x38,0x20,1}, - {73,0x6C,0x38,0x20,1}, {74,0x6D,0x38,0x20,1}, {75,0x6E,0x38,0x20,1}, - {76,0x6F,0x38,0x20,1}}; +boost::uint8_t gain_table_4000mhz_to_6000mhz[77][3] = { +{ 0x00, 0x00, 0x20 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, +{ 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x01, 0x00 }, +{ 0x00, 0x02, 0x00 }, { 0x00, 0x03, 0x00 }, { 0x01, 0x01, 0x20 }, +{ 0x01, 0x02, 0x00 }, { 0x01, 0x03, 0x00 }, { 0x01, 0x04, 0x20 }, +{ 0x01, 0x05, 0x00 }, { 0x01, 0x06, 0x00 }, { 0x01, 0x07, 0x00 }, +{ 0x01, 0x08, 0x00 }, { 0x01, 0x09, 0x00 }, { 0x01, 0x0A, 0x00 }, +{ 0x01, 0x0B, 0x00 }, { 0x01, 0x0C, 0x00 }, { 0x02, 0x08, 0x20 }, +{ 0x02, 0x09, 0x00 }, { 0x02, 0x0A, 0x00 }, { 0x02, 0x0B, 0x20 }, +{ 0x02, 0x0C, 0x00 }, { 0x02, 0x0D, 0x00 }, { 0x02, 0x0E, 0x00 }, +{ 0x02, 0x0F, 0x00 }, { 0x02, 0x2A, 0x20 }, { 0x02, 0x2B, 0x00 }, +{ 0x04, 0x27, 0x20 }, { 0x04, 0x28, 0x00 }, { 0x04, 0x29, 0x00 }, +{ 0x04, 0x2A, 0x00 }, { 0x04, 0x2B, 0x00 }, { 0x04, 0x2C, 0x00 }, +{ 0x04, 0x2D, 0x00 }, { 0x24, 0x20, 0x20 }, { 0x24, 0x21, 0x00 }, +{ 0x24, 0x22, 0x00 }, { 0x44, 0x20, 0x20 }, { 0x44, 0x21, 0x00 }, +{ 0x44, 0x22, 0x00 }, { 0x44, 0x23, 0x00 }, { 0x44, 0x24, 0x00 }, +{ 0x44, 0x25, 0x00 }, { 0x44, 0x26, 0x00 }, { 0x44, 0x27, 0x00 }, +{ 0x44, 0x28, 0x00 }, { 0x44, 0x29, 0x00 }, { 0x44, 0x2A, 0x00 }, +{ 0x44, 0x2B, 0x00 }, { 0x44, 0x2C, 0x00 }, { 0x44, 0x2D, 0x00 }, +{ 0x44, 0x2E, 0x00 }, { 0x64, 0x2E, 0x20 }, { 0x64, 0x2F, 0x00 }, +{ 0x64, 0x30, 0x00 }, { 0x64, 0x31, 0x00 }, { 0x64, 0x32, 0x00 }, +{ 0x64, 0x33, 0x00 }, { 0x64, 0x34, 0x00 }, { 0x64, 0x35, 0x00 }, +{ 0x64, 0x36, 0x00 }, { 0x64, 0x37, 0x00 }, { 0x64, 0x38, 0x00 }, +{ 0x65, 0x38, 0x20 }, { 0x66, 0x38, 0x20 }, { 0x67, 0x38, 0x20 }, +{ 0x68, 0x38, 0x20 }, { 0x69, 0x38, 0x20 }, { 0x6A, 0x38, 0x20 }, +{ 0x6B, 0x38, 0x20 }, { 0x6C, 0x38, 0x20 }, { 0x6D, 0x38, 0x20 }, +{ 0x6E, 0x38, 0x20 }, { 0x6F, 0x38, 0x20 } }; #endif /* INCLUDED_AD9361_GAIN_TABLES_HPP */ diff --git a/host/lib/usrp/e300/e300_impl.cpp b/host/lib/usrp/e300/e300_impl.cpp index ac6294d5a..ce94147e8 100644 --- a/host/lib/usrp/e300/e300_impl.cpp +++ b/host/lib/usrp/e300/e300_impl.cpp @@ -1028,6 +1028,8 @@ void e300_impl::_setup_radio(const size_t dspno) _tree->create<int>(rf_fe_path / "sensors"); //empty TODO _tree->create<sensor_value_t>(rf_fe_path / "sensors" / "lo_locked") .publish(boost::bind(&e300_impl::_get_fe_pll_lock, this, direction == "tx")); + _tree->create<sensor_value_t>(rf_fe_path / "sensors" / "temp") + .publish(boost::bind(&ad9361_ctrl::get_temperature, _codec_ctrl)); BOOST_FOREACH(const std::string &name, ad9361_ctrl::get_gain_names(key)) { _tree->create<meta_range_t>(rf_fe_path / "gains" / name / "range") diff --git a/host/lib/usrp/e300/e300_network.cpp b/host/lib/usrp/e300/e300_network.cpp index bb904773b..3396931e3 100644 --- a/host/lib/usrp/e300/e300_network.cpp +++ b/host/lib/usrp/e300/e300_network.cpp @@ -226,6 +226,14 @@ static void e300_codec_ctrl_tunnel( break; case codec_xact_t::ACTION_GET_RSSI: out->rssi = _codec_ctrl->get_rssi(which_str).to_real(); + case codec_xact_t::ACTION_GET_TEMPERATURE: + out->temp = _codec_ctrl->get_temperature().to_real(); + break; + case codec_xact_t::ACTION_SET_DC_OFFSET_AUTO: + _codec_ctrl->set_dc_offset_auto(which_str, in->use_dc_correction == 1); + break; + case codec_xact_t::ACTION_SET_IQ_BALANCE_AUTO: + _codec_ctrl->set_iq_balance_auto(which_str, in->use_iq_correction == 1); break; default: UHD_MSG(status) << "Got unknown request?!" << std::endl; diff --git a/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp b/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp index ed8131e2f..15222a96a 100644 --- a/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp +++ b/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp @@ -116,10 +116,48 @@ public: _args.bits = uhd::htonx<boost::uint32_t>(0); _transact(); - return sensor_value_t("RSSI", _retval.rssi, "dB"); } + sensor_value_t get_temperature() + { + _clear(); + _args.action = uhd::htonx<boost::uint32_t>(transaction_t::ACTION_GET_TEMPERATURE); + _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_NONE); /*Unused*/ + _args.bits = uhd::htonx<boost::uint32_t>(0); + + _transact(); + return sensor_value_t("temp", _retval.temp, "C"); + } + + void set_dc_offset_auto(const std::string &which, const bool on) + { + _clear(); + _args.action = uhd::htonx<boost::uint32_t>(transaction_t::ACTION_SET_DC_OFFSET_AUTO); + if (which == "TX1") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX1); + else if (which == "TX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX2); + else if (which == "RX1") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX1); + else if (which == "RX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX2); + else throw std::runtime_error("e300_remote_codec_ctrl_impl incorrect chain string."); + _args.use_dc_correction = on ? 1 : 0; + + _transact(); + } + + void set_iq_balance_auto(const std::string &which, const bool on) + { + _clear(); + _args.action = uhd::htonx<boost::uint32_t>(transaction_t::ACTION_SET_IQ_BALANCE_AUTO); + if (which == "TX1") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX1); + else if (which == "TX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_TX2); + else if (which == "RX1") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX1); + else if (which == "RX2") _args.which = uhd::htonx<boost::uint32_t>(transaction_t::CHAIN_RX2); + else throw std::runtime_error("e300_remote_codec_ctrl_impl incorrect chain string."); + _args.use_iq_correction = on ? 1 : 0; + + _transact(); + } + private: void _transact() { { diff --git a/host/lib/usrp/e300/e300_remote_codec_ctrl.hpp b/host/lib/usrp/e300/e300_remote_codec_ctrl.hpp index cbc4b52d2..855ab0f42 100644 --- a/host/lib/usrp/e300/e300_remote_codec_ctrl.hpp +++ b/host/lib/usrp/e300/e300_remote_codec_ctrl.hpp @@ -34,6 +34,9 @@ public: double gain; double freq; double rssi; + double temp; + boost::uint32_t use_dc_correction; + boost::uint32_t use_iq_correction; boost::uint64_t bits; }; @@ -44,6 +47,9 @@ public: static const boost::uint32_t ACTION_TUNE = 13; static const boost::uint32_t ACTION_SET_LOOPBACK = 14; static const boost::uint32_t ACTION_GET_RSSI = 15; + static const boost::uint32_t ACTION_GET_TEMPERATURE = 16; + static const boost::uint32_t ACTION_SET_DC_OFFSET_AUTO = 17; + static const boost::uint32_t ACTION_SET_IQ_BALANCE_AUTO = 18; //Values for "which" static const boost::uint32_t CHAIN_NONE = 0; diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp index 175633c4c..e7d39b244 100644 --- a/host/lib/usrp/multi_usrp.cpp +++ b/host/lib/usrp/multi_usrp.cpp @@ -431,6 +431,9 @@ public: ******************************************************************/ void set_master_clock_rate(double rate, size_t mboard){ if (mboard != ALL_MBOARDS){ + if (_tree->exists(mb_root(mboard) / "auto_tick_rate")) { + _tree->access<bool>(mb_root(mboard) / "auto_tick_rate").set(false); + } _tree->access<double>(mb_root(mboard) / "tick_rate").set(rate); return; } @@ -828,6 +831,16 @@ public: } } + void set_normalized_rx_gain(double gain, size_t chan = 0) + { + if (gain > 1.0 || gain < 0.0) { + throw uhd::runtime_error("Normalized gain out of range, must be in [0, 1]."); + } + gain_range_t gain_range = get_rx_gain_range(ALL_GAINS, chan); + double abs_gain = (gain * (gain_range.stop() - gain_range.start())) + gain_range.start(); + set_rx_gain(abs_gain, ALL_GAINS, chan); + } + double get_rx_gain(const std::string &name, size_t chan){ try { return rx_gain_group(chan)->get_value(name); @@ -836,6 +849,21 @@ public: } } + double get_normalized_rx_gain(size_t chan) + { + gain_range_t gain_range = get_rx_gain_range(ALL_GAINS, chan); + double gain_range_width = gain_range.stop() - gain_range.start(); + // In case we have a device without a range of gains: + if (gain_range_width == 0.0) { + return 0; + } + double norm_gain = (get_rx_gain(ALL_GAINS, chan) - gain_range.start()) / gain_range_width; + // Avoid rounding errors: + if (norm_gain > 1.0) return 1.0; + if (norm_gain < 0.0) return 0.0; + return norm_gain; + } + gain_range_t get_rx_gain_range(const std::string &name, size_t chan){ try { return rx_gain_group(chan)->get_range(name); @@ -888,6 +916,9 @@ public: if (chan != ALL_CHANS){ if (_tree->exists(rx_fe_root(chan) / "dc_offset" / "enable")) { _tree->access<bool>(rx_fe_root(chan) / "dc_offset" / "enable").set(enb); + } else if (_tree->exists(rx_rf_fe_root(chan) / "dc_offset" / "enable")) { + /*For B2xx devices the dc-offset correction is implemented in the rf front-end*/ + _tree->access<bool>(rx_rf_fe_root(chan) / "dc_offset" / "enable").set(enb); } else { UHD_MSG(warning) << "Setting DC offset compensation is not possible on this device." << std::endl; } @@ -912,6 +943,20 @@ public: } } + void set_rx_iq_balance(const bool enb, size_t chan){ + if (chan != ALL_CHANS){ + if (_tree->exists(rx_rf_fe_root(chan) / "iq_balance" / "enable")) { + _tree->access<bool>(rx_rf_fe_root(chan) / "iq_balance" / "enable").set(enb); + } else { + UHD_MSG(warning) << "Setting IQ imbalance compensation is not possible on this device." << std::endl; + } + return; + } + for (size_t c = 0; c < get_rx_num_channels(); c++){ + this->set_rx_iq_balance(enb, c); + } + } + void set_rx_iq_balance(const std::complex<double> &offset, size_t chan){ if (chan != ALL_CHANS){ if (_tree->exists(rx_fe_root(chan) / "iq_balance" / "value")) { @@ -1029,6 +1074,17 @@ public: } } + void set_normalized_tx_gain(double gain, size_t chan = 0) + { + if (gain > 1.0 || gain < 0.0) { + throw uhd::runtime_error("Normalized gain out of range, must be in [0, 1]."); + } + gain_range_t gain_range = get_tx_gain_range(ALL_GAINS, chan); + double abs_gain = (gain * (gain_range.stop() - gain_range.start())) + gain_range.start(); + set_tx_gain(abs_gain, ALL_GAINS, chan); + } + + double get_tx_gain(const std::string &name, size_t chan){ try { return tx_gain_group(chan)->get_value(name); @@ -1037,6 +1093,21 @@ public: } } + double get_normalized_tx_gain(size_t chan) + { + gain_range_t gain_range = get_tx_gain_range(ALL_GAINS, chan); + double gain_range_width = gain_range.stop() - gain_range.start(); + // In case we have a device without a range of gains: + if (gain_range_width == 0.0) { + return 0.0; + } + double norm_gain = (get_rx_gain(ALL_GAINS, chan) - gain_range.start()) / gain_range_width; + // Avoid rounding errors: + if (norm_gain > 1.0) return 1.0; + if (norm_gain < 0.0) return 0.0; + return norm_gain; + } + gain_range_t get_tx_gain_range(const std::string &name, size_t chan){ try { return tx_gain_group(chan)->get_range(name); diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp index e35f73eab..bf676b661 100644 --- a/host/lib/usrp/x300/x300_impl.cpp +++ b/host/lib/usrp/x300/x300_impl.cpp @@ -41,7 +41,7 @@ #define NIUSRPRIO_DEFAULT_RPC_PORT "5444" -#define X300_REV(x) (x - "A" + 1) +#define X300_REV(x) ((x) - "A" + 1) using namespace uhd; using namespace uhd::usrp; @@ -1432,8 +1432,8 @@ bool x300_impl::wait_for_ref_locked(wb_iface::sptr ctrl, double timeout) boost::this_thread::sleep(boost::posix_time::milliseconds(1)); } while (boost::get_system_time() < timeout_time); - //failed to lock on reference - return false; + //Check one last time + return get_ref_locked(ctrl).to_bool(); } sensor_value_t x300_impl::get_ref_locked(wb_iface::sptr ctrl) @@ -1720,14 +1720,20 @@ x300_impl::x300_mboard_t x300_impl::get_mb_type_from_pcie(const std::string& res case X300_USRP_PCIE_SSID: mb_type = USRP_X300_MB; break; case X310_USRP_PCIE_SSID: - case X310_2940R_PCIE_SSID: - case X310_2942R_PCIE_SSID: - case X310_2943R_PCIE_SSID: - case X310_2944R_PCIE_SSID: - case X310_2950R_PCIE_SSID: - case X310_2952R_PCIE_SSID: - case X310_2953R_PCIE_SSID: - case X310_2954R_PCIE_SSID: + case X310_2940R_40MHz_PCIE_SSID: + case X310_2940R_120MHz_PCIE_SSID: + case X310_2942R_40MHz_PCIE_SSID: + case X310_2942R_120MHz_PCIE_SSID: + case X310_2943R_40MHz_PCIE_SSID: + case X310_2943R_120MHz_PCIE_SSID: + case X310_2944R_40MHz_PCIE_SSID: + case X310_2950R_40MHz_PCIE_SSID: + case X310_2950R_120MHz_PCIE_SSID: + case X310_2952R_40MHz_PCIE_SSID: + case X310_2952R_120MHz_PCIE_SSID: + case X310_2953R_40MHz_PCIE_SSID: + case X310_2953R_120MHz_PCIE_SSID: + case X310_2954R_40MHz_PCIE_SSID: mb_type = USRP_X310_MB; break; default: mb_type = UNKNOWN; break; @@ -1755,14 +1761,20 @@ x300_impl::x300_mboard_t x300_impl::get_mb_type_from_eeprom(const uhd::usrp::mbo case X300_USRP_PCIE_SSID: mb_type = USRP_X300_MB; break; case X310_USRP_PCIE_SSID: - case X310_2940R_PCIE_SSID: - case X310_2942R_PCIE_SSID: - case X310_2943R_PCIE_SSID: - case X310_2944R_PCIE_SSID: - case X310_2950R_PCIE_SSID: - case X310_2952R_PCIE_SSID: - case X310_2953R_PCIE_SSID: - case X310_2954R_PCIE_SSID: + case X310_2940R_40MHz_PCIE_SSID: + case X310_2940R_120MHz_PCIE_SSID: + case X310_2942R_40MHz_PCIE_SSID: + case X310_2942R_120MHz_PCIE_SSID: + case X310_2943R_40MHz_PCIE_SSID: + case X310_2943R_120MHz_PCIE_SSID: + case X310_2944R_40MHz_PCIE_SSID: + case X310_2950R_40MHz_PCIE_SSID: + case X310_2950R_120MHz_PCIE_SSID: + case X310_2952R_40MHz_PCIE_SSID: + case X310_2952R_120MHz_PCIE_SSID: + case X310_2953R_40MHz_PCIE_SSID: + case X310_2953R_120MHz_PCIE_SSID: + case X310_2954R_40MHz_PCIE_SSID: mb_type = USRP_X310_MB; break; default: UHD_MSG(warning) << "X300 unknown product code in EEPROM: " << product_num << std::endl; diff --git a/host/lib/usrp/x300/x300_io_impl.cpp b/host/lib/usrp/x300/x300_io_impl.cpp index 334ae8168..e3515af0c 100644 --- a/host/lib/usrp/x300/x300_io_impl.cpp +++ b/host/lib/usrp/x300/x300_io_impl.cpp @@ -23,6 +23,7 @@ #include <uhd/transport/nirio_zero_copy.hpp> #include "async_packet_handler.hpp" #include <uhd/transport/bounded_buffer.hpp> +#include <uhd/transport/chdr.hpp> #include <boost/bind.hpp> #include <uhd/utils/tasks.hpp> #include <uhd/utils/log.hpp> @@ -124,41 +125,6 @@ void x300_impl::update_subdev_spec(const std::string &tx_rx, const size_t mb_i, /*********************************************************************** - * VITA stuff - **********************************************************************/ -static void x300_if_hdr_unpack_be( - const boost::uint32_t *packet_buff, - vrt::if_packet_info_t &if_packet_info -){ - if_packet_info.link_type = vrt::if_packet_info_t::LINK_TYPE_CHDR; - return vrt::if_hdr_unpack_be(packet_buff, if_packet_info); -} - -static void x300_if_hdr_pack_be( - boost::uint32_t *packet_buff, - vrt::if_packet_info_t &if_packet_info -){ - if_packet_info.link_type = vrt::if_packet_info_t::LINK_TYPE_CHDR; - return vrt::if_hdr_pack_be(packet_buff, if_packet_info); -} - -static void x300_if_hdr_unpack_le( - const boost::uint32_t *packet_buff, - vrt::if_packet_info_t &if_packet_info -){ - if_packet_info.link_type = vrt::if_packet_info_t::LINK_TYPE_CHDR; - return vrt::if_hdr_unpack_le(packet_buff, if_packet_info); -} - -static void x300_if_hdr_pack_le( - boost::uint32_t *packet_buff, - vrt::if_packet_info_t &if_packet_info -){ - if_packet_info.link_type = vrt::if_packet_info_t::LINK_TYPE_CHDR; - return vrt::if_hdr_pack_le(packet_buff, if_packet_info); -} - -/*********************************************************************** * RX flow control handler **********************************************************************/ static size_t get_rx_flow_control_window(size_t frame_size, size_t sw_buff_size, const device_addr_t& rx_args) @@ -209,9 +175,9 @@ static void handle_rx_flowctrl(const boost::uint32_t sid, zero_copy_if::sptr xpo //load header if (big_endian) - x300_if_hdr_pack_be(pkt, packet_info); + vrt::chdr::if_hdr_pack_be(pkt, packet_info); else - x300_if_hdr_pack_le(pkt, packet_info); + vrt::chdr::if_hdr_pack_le(pkt, packet_info); //load payload pkt[packet_info.num_header_words32+0] = uhd::htonx<boost::uint32_t>(0); @@ -276,12 +242,12 @@ static void handle_tx_async_msgs(boost::shared_ptr<x300_tx_fc_guts_t> guts, zero { if (big_endian) { - x300_if_hdr_unpack_be(packet_buff, if_packet_info); + vrt::chdr::if_hdr_unpack_be(packet_buff, if_packet_info); endian_conv = uhd::ntohx; } else { - x300_if_hdr_unpack_le(packet_buff, if_packet_info); + vrt::chdr::if_hdr_unpack_le(packet_buff, if_packet_info); endian_conv = uhd::wtohx; } } @@ -430,10 +396,10 @@ rx_streamer::sptr x300_impl::get_rx_stream(const uhd::stream_args_t &args_) //init some streamer stuff std::string conv_endianness; if (mb.if_pkt_is_big_endian) { - my_streamer->set_vrt_unpacker(&x300_if_hdr_unpack_be); + my_streamer->set_vrt_unpacker(&vrt::chdr::if_hdr_unpack_be); conv_endianness = "be"; } else { - my_streamer->set_vrt_unpacker(&x300_if_hdr_unpack_le); + my_streamer->set_vrt_unpacker(&vrt::chdr::if_hdr_unpack_le); conv_endianness = "le"; } @@ -594,10 +560,10 @@ tx_streamer::sptr x300_impl::get_tx_stream(const uhd::stream_args_t &args_) std::string conv_endianness; if (mb.if_pkt_is_big_endian) { - my_streamer->set_vrt_packer(&x300_if_hdr_pack_be); + my_streamer->set_vrt_packer(&vrt::chdr::if_hdr_pack_be); conv_endianness = "be"; } else { - my_streamer->set_vrt_packer(&x300_if_hdr_pack_le); + my_streamer->set_vrt_packer(&vrt::chdr::if_hdr_pack_le); conv_endianness = "le"; } diff --git a/host/lib/usrp/x300/x300_regs.hpp b/host/lib/usrp/x300/x300_regs.hpp index f920b5ae2..4c5729efe 100644 --- a/host/lib/usrp/x300/x300_regs.hpp +++ b/host/lib/usrp/x300/x300_regs.hpp @@ -25,40 +25,40 @@ #define localparam static const int -localparam SR_DACSYNC = 5; -localparam SR_LOOPBACK = 6; -localparam SR_TEST = 7; -localparam SR_SPI = 8; -localparam SR_GPIO = 16; -localparam SR_MISC_OUTS = 24; -localparam SR_READBACK = 32; -localparam SR_TX_CTRL = 64; -localparam SR_RX_CTRL = 96; -localparam SR_TIME = 128; -localparam SR_RX_DSP = 144; -localparam SR_TX_DSP = 184; -localparam SR_LEDS = 195; -localparam SR_FP_GPIO = 200; -localparam SR_RX_FRONT = 208; -localparam SR_TX_FRONT = 216; - -localparam RB32_GPIO = 0; -localparam RB32_SPI = 4; -localparam RB64_TIME_NOW = 8; -localparam RB64_TIME_PPS = 16; -localparam RB32_TEST = 24; -localparam RB32_RX = 28; -localparam RB32_FP_GPIO = 32; - -localparam BL_ADDRESS = 0; -localparam BL_DATA = 1; +localparam SR_DACSYNC = 5; +localparam SR_LOOPBACK = 6; +localparam SR_TEST = 7; +localparam SR_SPI = 8; +localparam SR_GPIO = 16; +localparam SR_MISC_OUTS = 24; +localparam SR_READBACK = 32; +localparam SR_TX_CTRL = 64; +localparam SR_RX_CTRL = 96; +localparam SR_TIME = 128; +localparam SR_RX_DSP = 144; +localparam SR_TX_DSP = 184; +localparam SR_LEDS = 195; +localparam SR_FP_GPIO = 200; +localparam SR_RX_FRONT = 208; +localparam SR_TX_FRONT = 216; + +localparam RB32_GPIO = 0; +localparam RB32_SPI = 4; +localparam RB64_TIME_NOW = 8; +localparam RB64_TIME_PPS = 16; +localparam RB32_TEST = 24; +localparam RB32_RX = 28; +localparam RB32_FP_GPIO = 32; + +localparam BL_ADDRESS = 0; +localparam BL_DATA = 1; //wishbone settings map - relevant to host code -#define SET0_BASE 0xa000 -#define SETXB_BASE 0xb000 -#define BOOT_LDR_BASE 0xFA00 -#define I2C0_BASE 0xfe00 -#define I2C1_BASE 0xff00 +#define SET0_BASE 0xa000 +#define SETXB_BASE 0xb000 +#define BOOT_LDR_BASE 0xfa00 +#define I2C0_BASE 0xfe00 +#define I2C1_BASE 0xff00 #define SR_ADDR(base, offset) ((base) + (offset)*4) localparam ZPU_SR_LEDS = 00; @@ -70,56 +70,62 @@ localparam ZPU_SR_ETHINT0 = 40; localparam ZPU_SR_ETHINT1 = 56; //clock controls -#define ZPU_SR_CLOCK_CTRL_CLK_SRC_EXTERNAL 0x00 -#define ZPU_SR_CLOCK_CTRL_CLK_SRC_INTERNAL 0x02 -#define ZPU_SR_CLOCK_CTRL_CLK_SRC_GPSDO 0x03 -#define ZPU_SR_CLOCK_CTRL_PPS_SRC_EXTERNAL 0x00 -#define ZPU_SR_CLOCK_CTRL_PPS_SRC_INTERNAL 0x02 -#define ZPU_SR_CLOCK_CTRL_PPS_SRC_GPSDO 0x03 - -localparam ZPU_RB_SPI = 2; +#define ZPU_SR_CLOCK_CTRL_CLK_SRC_EXTERNAL 0x00 +#define ZPU_SR_CLOCK_CTRL_CLK_SRC_INTERNAL 0x02 +#define ZPU_SR_CLOCK_CTRL_CLK_SRC_GPSDO 0x03 +#define ZPU_SR_CLOCK_CTRL_PPS_SRC_EXTERNAL 0x00 +#define ZPU_SR_CLOCK_CTRL_PPS_SRC_INTERNAL 0x02 +#define ZPU_SR_CLOCK_CTRL_PPS_SRC_GPSDO 0x03 + +localparam ZPU_RB_SPI = 2; localparam ZPU_RB_CLK_STATUS = 3; localparam ZPU_RB_COMPAT_NUM = 6; localparam ZPU_RB_ETH_TYPE0 = 4; localparam ZPU_RB_ETH_TYPE1 = 5; //clock status -#define ZPU_RB_CLK_STATUS_LMK_STATUS (0x3 << 0) -#define ZPU_RB_CLK_STATUS_LMK_LOCK (0x1 << 2) -#define ZPU_RB_CLK_STATUS_LMK_HOLDOVER (0x1 << 3) -#define ZPU_RB_CLK_STATUS_PPS_DETECT (0x1 << 4) +#define ZPU_RB_CLK_STATUS_LMK_STATUS (0x3 << 0) +#define ZPU_RB_CLK_STATUS_LMK_LOCK (0x1 << 2) +#define ZPU_RB_CLK_STATUS_LMK_HOLDOVER (0x1 << 3) +#define ZPU_RB_CLK_STATUS_PPS_DETECT (0x1 << 4) //spi slaves on radio -#define DB_DAC_SEN (1 << 7) -#define DB_ADC_SEN (1 << 6) +#define DB_DAC_SEN (1 << 7) +#define DB_ADC_SEN (1 << 6) #define DB_RX_LSADC_SEN (1 << 5) #define DB_RX_LSDAC_SEN (1 << 4) #define DB_TX_LSADC_SEN (1 << 3) #define DB_TX_LSDAC_SEN (1 << 2) -#define DB_RX_SEN (1 << 1) -#define DB_TX_SEN (1 << 0) +#define DB_RX_SEN (1 << 1) +#define DB_TX_SEN (1 << 0) //------------------------------------------------------------------- // PCIe Registers //------------------------------------------------------------------- -static const uint32_t X300_PCIE_VID = 0x1093; -static const uint32_t X300_PCIE_PID = 0xC4C4; -static const uint32_t X300_USRP_PCIE_SSID = 0x7736; -static const uint32_t X310_USRP_PCIE_SSID = 0x76CA; -static const uint32_t X310_2940R_PCIE_SSID = 0x772B; -static const uint32_t X310_2942R_PCIE_SSID = 0x772C; -static const uint32_t X310_2943R_PCIE_SSID = 0x772D; -static const uint32_t X310_2944R_PCIE_SSID = 0x772E; -static const uint32_t X310_2950R_PCIE_SSID = 0x772F; -static const uint32_t X310_2952R_PCIE_SSID = 0x7730; -static const uint32_t X310_2953R_PCIE_SSID = 0x7731; -static const uint32_t X310_2954R_PCIE_SSID = 0x7732; +static const uint32_t X300_PCIE_VID = 0x1093; +static const uint32_t X300_PCIE_PID = 0xC4C4; +static const uint32_t X300_USRP_PCIE_SSID = 0x7736; +static const uint32_t X310_USRP_PCIE_SSID = 0x76CA; +static const uint32_t X310_2940R_40MHz_PCIE_SSID = 0x772B; +static const uint32_t X310_2940R_120MHz_PCIE_SSID = 0x77FB; +static const uint32_t X310_2942R_40MHz_PCIE_SSID = 0x772C; +static const uint32_t X310_2942R_120MHz_PCIE_SSID = 0x77FC; +static const uint32_t X310_2943R_40MHz_PCIE_SSID = 0x772D; +static const uint32_t X310_2943R_120MHz_PCIE_SSID = 0x77FD; +static const uint32_t X310_2944R_40MHz_PCIE_SSID = 0x772E; +static const uint32_t X310_2950R_40MHz_PCIE_SSID = 0x772F; +static const uint32_t X310_2950R_120MHz_PCIE_SSID = 0x77FE; +static const uint32_t X310_2952R_40MHz_PCIE_SSID = 0x7730; +static const uint32_t X310_2952R_120MHz_PCIE_SSID = 0x77FF; +static const uint32_t X310_2953R_40MHz_PCIE_SSID = 0x7731; +static const uint32_t X310_2953R_120MHz_PCIE_SSID = 0x7800; +static const uint32_t X310_2954R_40MHz_PCIE_SSID = 0x7732; static const uint32_t FPGA_X3xx_SIG_VALUE = 0x58333030; static const uint32_t PCIE_FPGA_ADDR_BASE = 0xC0000; -#define PCIE_FPGA_REG(X) (PCIE_FPGA_ADDR_BASE + X) +#define PCIE_FPGA_REG(X) (PCIE_FPGA_ADDR_BASE + (X)) static const uint32_t FPGA_PCIE_SIG_REG = PCIE_FPGA_REG(0x0000); static const uint32_t FPGA_CNTR_LO_REG = PCIE_FPGA_REG(0x0004); @@ -140,8 +146,8 @@ static const uint32_t DMA_FRAME_SIZE_REG = 0x4; static const uint32_t DMA_SAMPLE_COUNT_REG = 0x8; static const uint32_t DMA_PKT_COUNT_REG = 0xC; -#define PCIE_TX_DMA_REG(REG, CHAN) (PCIE_TX_DMA_REG_BASE + (CHAN*DMA_REG_GRP_SIZE) + REG) -#define PCIE_RX_DMA_REG(REG, CHAN) (PCIE_RX_DMA_REG_BASE + (CHAN*DMA_REG_GRP_SIZE) + REG) +#define PCIE_TX_DMA_REG(REG, CHAN) (PCIE_TX_DMA_REG_BASE + ((CHAN)*DMA_REG_GRP_SIZE) + (REG)) +#define PCIE_RX_DMA_REG(REG, CHAN) (PCIE_RX_DMA_REG_BASE + ((CHAN)*DMA_REG_GRP_SIZE) + (REG)) static const uint32_t DMA_CTRL_DISABLED = 0x00000000; static const uint32_t DMA_CTRL_ENABLED = 0x00000002; @@ -154,15 +160,15 @@ static const uint32_t DMA_STATUS_ERROR = 0x00000001; static const uint32_t DMA_STATUS_BUSY = 0x00000002; static const uint32_t PCIE_ROUTER_REG_BASE = PCIE_FPGA_REG(0x0500); -#define PCIE_ROUTER_REG(X) (PCIE_ROUTER_REG_BASE + X) +#define PCIE_ROUTER_REG(X) (PCIE_ROUTER_REG_BASE + (X)) static const uint32_t PCIE_ZPU_DATA_BASE = 0x30000; static const uint32_t PCIE_ZPU_READ_BASE = 0x20000; //Trig and Status share the same base static const uint32_t PCIE_ZPU_STATUS_BASE = 0x20000; -#define PCIE_ZPU_DATA_REG(X) (PCIE_FPGA_REG(PCIE_ZPU_DATA_BASE) + X) -#define PCIE_ZPU_READ_REG(X) (PCIE_FPGA_REG(PCIE_ZPU_READ_BASE) + X) -#define PCIE_ZPU_STATUS_REG(X) (PCIE_FPGA_REG(PCIE_ZPU_STATUS_BASE) + X) +#define PCIE_ZPU_DATA_REG(X) (PCIE_FPGA_REG(PCIE_ZPU_DATA_BASE) + (X)) +#define PCIE_ZPU_READ_REG(X) (PCIE_FPGA_REG(PCIE_ZPU_READ_BASE) + (X)) +#define PCIE_ZPU_STATUS_REG(X) (PCIE_FPGA_REG(PCIE_ZPU_STATUS_BASE) + (X)) static const uint32_t PCIE_ZPU_READ_START = 0x0; static const uint32_t PCIE_ZPU_READ_CLOBBER = 0x80000000; |