diff options
-rw-r--r-- | host/examples/rx_samples_to_file.cpp | 4 | ||||
-rw-r--r-- | host/lib/usrp/b100/b100_impl.cpp | 6 | ||||
-rw-r--r-- | host/lib/usrp/dboard/db_dbsrx2.cpp | 6 | ||||
-rw-r--r-- | host/lib/usrp/dboard/db_sbx_common.cpp | 132 | ||||
-rw-r--r-- | host/lib/usrp/dboard/db_sbx_common.hpp | 28 | ||||
-rw-r--r-- | host/lib/usrp/dboard/db_sbx_version3.cpp | 118 | ||||
-rw-r--r-- | host/lib/usrp/dboard/db_sbx_version4.cpp | 120 | ||||
-rw-r--r-- | host/lib/usrp/usrp1/usrp1_impl.cpp | 8 | ||||
-rw-r--r-- | host/lib/utils/paths.cpp | 22 | ||||
-rw-r--r-- | host/utils/uhd_images_downloader.py.in | 63 | ||||
-rw-r--r-- | host/utils/usrp_burn_mb_eeprom.cpp | 43 |
11 files changed, 321 insertions, 229 deletions
diff --git a/host/examples/rx_samples_to_file.cpp b/host/examples/rx_samples_to_file.cpp index b0e498125..a28d1d628 100644 --- a/host/examples/rx_samples_to_file.cpp +++ b/host/examples/rx_samples_to_file.cpp @@ -236,8 +236,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ ("ref", po::value<std::string>(&ref)->default_value("internal"), "waveform type (internal, external, mimo)") ("wirefmt", po::value<std::string>(&wirefmt)->default_value("sc16"), "wire format (sc8 or sc16)") ("setup", po::value<double>(&setup_time)->default_value(1.0), "seconds of setup time") - ("progress", "show average bandwidth on exit") - ("stats", "periodically display short-term bandwidth") + ("progress", "periodically display short-term bandwidth") + ("stats", "show average bandwidth on exit") ("sizemap", "track packet size and display breakdown on exit") ("null", "run without writing to file") ("continue", "don't abort on a bad packet") diff --git a/host/lib/usrp/b100/b100_impl.cpp b/host/lib/usrp/b100/b100_impl.cpp index 19df3d6af..305ba42a7 100644 --- a/host/lib/usrp/b100/b100_impl.cpp +++ b/host/lib/usrp/b100/b100_impl.cpp @@ -310,12 +310,14 @@ b100_impl::b100_impl(const device_addr_t &device_addr){ _tree->create<std::string>(rx_codec_path / "name").set("ad9522"); _tree->create<meta_range_t>(rx_codec_path / "gains/pga/range").set(b100_codec_ctrl::rx_pga_gain_range); _tree->create<double>(rx_codec_path / "gains/pga/value") - .coerce(boost::bind(&b100_impl::update_rx_codec_gain, this, _1)); + .coerce(boost::bind(&b100_impl::update_rx_codec_gain, this, _1)) + .set(0.0); _tree->create<std::string>(tx_codec_path / "name").set("ad9522"); _tree->create<meta_range_t>(tx_codec_path / "gains/pga/range").set(b100_codec_ctrl::tx_pga_gain_range); _tree->create<double>(tx_codec_path / "gains/pga/value") .subscribe(boost::bind(&b100_codec_ctrl::set_tx_pga_gain, _codec_ctrl, _1)) - .publish(boost::bind(&b100_codec_ctrl::get_tx_pga_gain, _codec_ctrl)); + .publish(boost::bind(&b100_codec_ctrl::get_tx_pga_gain, _codec_ctrl)) + .set(0.0); //////////////////////////////////////////////////////////////////// // and do the misc mboard sensors diff --git a/host/lib/usrp/dboard/db_dbsrx2.cpp b/host/lib/usrp/dboard/db_dbsrx2.cpp index 013f3178a..8a8f61a69 100644 --- a/host/lib/usrp/dboard/db_dbsrx2.cpp +++ b/host/lib/usrp/dboard/db_dbsrx2.cpp @@ -358,12 +358,12 @@ double dbsrx2::set_gain(double gain, const std::string &name){ * Bandwidth Handling **********************************************************************/ double dbsrx2::set_bandwidth(double bandwidth){ - //convert complex bandpass to lowpass bandwidth - bandwidth = bandwidth/2.0; - //clip the input bandwidth = dbsrx2_bandwidth_range.clip(bandwidth); + //convert complex bandpass to lowpass bandwidth + bandwidth = bandwidth/2.0; + _max2112_write_regs.lp = int((bandwidth/1e6 - 4)/0.29 + 12); _bandwidth = double(4 + (_max2112_write_regs.lp - 12) * 0.29)*1e6; diff --git a/host/lib/usrp/dboard/db_sbx_common.cpp b/host/lib/usrp/dboard/db_sbx_common.cpp index 9db29e65a..5b713c6d7 100644 --- a/host/lib/usrp/dboard/db_sbx_common.cpp +++ b/host/lib/usrp/dboard/db_sbx_common.cpp @@ -21,6 +21,137 @@ using namespace uhd; using namespace uhd::usrp; using namespace boost::assign; +/*********************************************************************** + * ADF 4350/4351 Tuning Utility + **********************************************************************/ +sbx_xcvr::sbx_versionx::adf435x_tuning_settings sbx_xcvr::sbx_versionx::_tune_adf435x_synth( + double target_freq, + double ref_freq, + const adf435x_tuning_constraints& constraints, + double& actual_freq) +{ + //Default invalid value for actual_freq + actual_freq = 0; + + double pfd_freq = 0; + boost::uint16_t R = 0, BS = 0, N = 0, FRAC = 0, MOD = 0; + boost::uint16_t RFdiv = static_cast<boost::uint16_t>(constraints.rf_divider_range.start()); + bool D = false, T = false; + + //Reference doubler for 50% duty cycle + //If ref_freq < 12.5MHz enable the reference doubler + D = (ref_freq <= constraints.ref_doubler_threshold); + + static const double MIN_VCO_FREQ = 2.2e9; + static const double MAX_VCO_FREQ = 4.4e9; + + //increase RF divider until acceptable VCO frequency + double vco_freq = target_freq; + while (vco_freq < MIN_VCO_FREQ && RFdiv < static_cast<boost::uint16_t>(constraints.rf_divider_range.stop())) { + vco_freq *= 2; + RFdiv *= 2; + } + + /* + * The goal here is to loop though possible R dividers, + * band select clock dividers, N (int) dividers, and FRAC + * (frac) dividers. + * + * Calculate the N and F dividers for each set of values. + * The loop exits when it meets all of the constraints. + * The resulting loop values are loaded into the registers. + * + * from pg.21 + * + * f_pfd = f_ref*(1+D)/(R*(1+T)) + * f_vco = (N + (FRAC/MOD))*f_pfd + * N = f_vco/f_pfd - FRAC/MOD = f_vco*((R*(T+1))/(f_ref*(1+D))) - FRAC/MOD + * f_rf = f_vco/RFdiv) + * f_actual = f_rf/2 + */ + for(R = 1; R <= 1023; R+=1){ + //PFD input frequency = f_ref/R ... ignoring Reference doubler/divide-by-2 (D & T) + pfd_freq = ref_freq*(D?2:1)/(R*(T?2:1)); + + //keep the PFD frequency at or below 25MHz (Loop Filter Bandwidth) + if (pfd_freq > constraints.pfd_freq_max) continue; + + //ignore fractional part of tuning + //N is computed from target_freq and not vco_freq because the feedback + //mode is set to FEEDBACK_SELECT_DIVIDED + N = boost::uint16_t(std::floor(target_freq/pfd_freq)); + + //keep N > minimum int divider requirement + if (N < static_cast<boost::uint16_t>(constraints.int_range.start())) continue; + + for(BS=1; BS <= 255; BS+=1){ + //keep the band select frequency at or below band_sel_freq_max + //constraint on band select clock + if (pfd_freq/BS > constraints.band_sel_freq_max) continue; + goto done_loop; + } + } done_loop: + + //Fractional-N calculation + MOD = 4095; //max fractional accuracy + //N is computed from target_freq and not vco_freq because the feedback + //mode is set to FEEDBACK_SELECT_DIVIDED + FRAC = static_cast<boost::uint16_t>((target_freq/pfd_freq - N)*MOD); + if (constraints.force_frac0) { + if (FRAC > (MOD / 2)) { //Round integer such that actual freq is closest to target + N++; + } + FRAC = 0; + } + + //Reference divide-by-2 for 50% duty cycle + // if R even, move one divide by 2 to to regs.reference_divide_by_2 + if(R % 2 == 0) { + T = true; + R /= 2; + } + + //Typical phase resync time documented in data sheet pg.24 + static const double PHASE_RESYNC_TIME = 400e-6; + + //actual frequency calculation + actual_freq = double((N + (double(FRAC)/double(MOD)))*ref_freq*(D?2:1)/(R*(T?2:1))); + + //load the settings + adf435x_tuning_settings settings; + settings.frac_12_bit = FRAC; + settings.int_16_bit = N; + settings.mod_12_bit = MOD; + settings.clock_divider_12_bit = std::max<boost::uint16_t>(1, std::ceil(PHASE_RESYNC_TIME*pfd_freq/MOD)); + settings.r_counter_10_bit = R; + settings.r_divide_by_2_en = T; + settings.r_doubler_en = D; + settings.band_select_clock_div = BS; + settings.rf_divider = RFdiv; + settings.feedback_after_divider = true; + + UHD_LOGV(often) + << boost::format("ADF 435X Frequencies (MHz): REQUESTED=%0.9f, ACTUAL=%0.9f" + ) % (target_freq/1e6) % (actual_freq/1e6) << std::endl + << boost::format("ADF 435X Intermediates (MHz): VCO=%0.2f, PFD=%0.2f, BAND=%0.2f, REF=%0.2f" + ) % (vco_freq/1e6) % (pfd_freq/1e6) % (pfd_freq/BS/1e6) % (ref_freq/1e6) << std::endl + << boost::format("ADF 435X Settings: R=%d, BS=%d, N=%d, FRAC=%d, MOD=%d, T=%d, D=%d, RFdiv=%d" + ) % R % BS % N % FRAC % MOD % T % D % RFdiv << std::endl; + + UHD_ASSERT_THROW((settings.frac_12_bit & ((boost::uint16_t)~0xFFF)) == 0); + UHD_ASSERT_THROW((settings.mod_12_bit & ((boost::uint16_t)~0xFFF)) == 0); + UHD_ASSERT_THROW((settings.clock_divider_12_bit & ((boost::uint16_t)~0xFFF)) == 0); + UHD_ASSERT_THROW((settings.r_counter_10_bit & ((boost::uint16_t)~0x3FF)) == 0); + + UHD_ASSERT_THROW(vco_freq >= MIN_VCO_FREQ and vco_freq <= MAX_VCO_FREQ); + UHD_ASSERT_THROW(settings.rf_divider >= static_cast<boost::uint16_t>(constraints.rf_divider_range.start())); + UHD_ASSERT_THROW(settings.rf_divider <= static_cast<boost::uint16_t>(constraints.rf_divider_range.stop())); + UHD_ASSERT_THROW(settings.int_16_bit >= static_cast<boost::uint16_t>(constraints.int_range.start())); + UHD_ASSERT_THROW(settings.int_16_bit <= static_cast<boost::uint16_t>(constraints.int_range.stop())); + + return settings; +} + /*********************************************************************** * Register the SBX dboard (min freq, max freq, rx div2, tx div2) @@ -362,4 +493,3 @@ void sbx_xcvr::flash_leds(void) { this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, (TXIO_MASK|TX_LED_IO)); this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, (RXIO_MASK|RX_LED_IO)); } - diff --git a/host/lib/usrp/dboard/db_sbx_common.hpp b/host/lib/usrp/dboard/db_sbx_common.hpp index 4f3a2eeaa..e9bb2434c 100644 --- a/host/lib/usrp/dboard/db_sbx_common.hpp +++ b/host/lib/usrp/dboard/db_sbx_common.hpp @@ -181,6 +181,34 @@ protected: ~sbx_versionx(void) {} virtual double set_lo_freq(dboard_iface::unit_t unit, double target_freq) = 0; + protected: + struct adf435x_tuning_constraints { + bool force_frac0; + double ref_doubler_threshold; + double pfd_freq_max; + double band_sel_freq_max; + uhd::range_t rf_divider_range; + uhd::range_t int_range; + }; + + struct adf435x_tuning_settings { + boost::uint16_t frac_12_bit; + boost::uint16_t int_16_bit; + boost::uint16_t mod_12_bit; + boost::uint16_t r_counter_10_bit; + bool r_doubler_en; + bool r_divide_by_2_en; + boost::uint16_t clock_divider_12_bit; + boost::uint8_t band_select_clock_div; + boost::uint16_t rf_divider; + bool feedback_after_divider; + }; + + adf435x_tuning_settings _tune_adf435x_synth( + double target_freq, + double ref_freq, + const adf435x_tuning_constraints& constraints, + double& actual_freq); }; /*! diff --git a/host/lib/usrp/dboard/db_sbx_version3.cpp b/host/lib/usrp/dboard/db_sbx_version3.cpp index 2765d530c..b0c9cd18f 100644 --- a/host/lib/usrp/dboard/db_sbx_version3.cpp +++ b/host/lib/usrp/dboard/db_sbx_version3.cpp @@ -63,85 +63,21 @@ double sbx_xcvr::sbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar (16, adf4350_regs_t::RF_DIVIDER_SELECT_DIV16) ; - double actual_freq, pfd_freq; - double ref_freq = self_base->get_iface()->get_clock_rate(unit); - int R=0, BS=0, N=0, FRAC=0, MOD=0; - int RFdiv = 1; - adf4350_regs_t::reference_divide_by_2_t T = adf4350_regs_t::REFERENCE_DIVIDE_BY_2_DISABLED; - adf4350_regs_t::reference_doubler_t D = adf4350_regs_t::REFERENCE_DOUBLER_DISABLED; - - //Reference doubler for 50% duty cycle - // if ref_freq < 12.5MHz enable regs.reference_divide_by_2 - if(ref_freq <= 12.5e6) D = adf4350_regs_t::REFERENCE_DOUBLER_ENABLED; - - //increase RF divider until acceptable VCO frequency - double vco_freq = target_freq; - while (vco_freq < 2.2e9) { - vco_freq *= 2; - RFdiv *= 2; - } - //use 8/9 prescaler for vco_freq > 3 GHz (pg.18 prescaler) adf4350_regs_t::prescaler_t prescaler = target_freq > 3e9 ? adf4350_regs_t::PRESCALER_8_9 : adf4350_regs_t::PRESCALER_4_5; - /* - * The goal here is to loop though possible R dividers, - * band select clock dividers, N (int) dividers, and FRAC - * (frac) dividers. - * - * Calculate the N and F dividers for each set of values. - * The loop exits when it meets all of the constraints. - * The resulting loop values are loaded into the registers. - * - * from pg.21 - * - * f_pfd = f_ref*(1+D)/(R*(1+T)) - * f_vco = (N + (FRAC/MOD))*f_pfd - * N = f_vco/f_pfd - FRAC/MOD = f_vco*((R*(T+1))/(f_ref*(1+D))) - FRAC/MOD - * f_rf = f_vco/RFdiv) - * f_actual = f_rf/2 - */ - for(R = 1; R <= 1023; R+=1){ - //PFD input frequency = f_ref/R ... ignoring Reference doubler/divide-by-2 (D & T) - pfd_freq = ref_freq*(1+D)/(R*(1+T)); - - //keep the PFD frequency at or below 25MHz (Loop Filter Bandwidth) - if (pfd_freq > 25e6) continue; - - //ignore fractional part of tuning - N = int(std::floor(target_freq/pfd_freq)); - - //keep N > minimum int divider requirement - if (N < prescaler_to_min_int_div[prescaler]) continue; - - for(BS=1; BS <= 255; BS+=1){ - //keep the band select frequency at or below 100KHz - //constraint on band select clock - if (pfd_freq/BS > 100e3) continue; - goto done_loop; - } - } done_loop: - - //Fractional-N calculation - MOD = 4095; //max fractional accuracy - FRAC = int((target_freq/pfd_freq - N)*MOD); - - //Reference divide-by-2 for 50% duty cycle - // if R even, move one divide by 2 to to regs.reference_divide_by_2 - if(R % 2 == 0){ - T = adf4350_regs_t::REFERENCE_DIVIDE_BY_2_ENABLED; - R /= 2; - } - - //actual frequency calculation - actual_freq = double((N + (double(FRAC)/double(MOD)))*ref_freq*(1+int(D))/(R*(1+int(T)))); + adf435x_tuning_constraints tuning_constraints; + tuning_constraints.force_frac0 = false; + tuning_constraints.band_sel_freq_max = 100e3; + tuning_constraints.ref_doubler_threshold = 12.5e6; + tuning_constraints.int_range = uhd::range_t(prescaler_to_min_int_div[prescaler], 4095); //INT is a 12-bit field + tuning_constraints.pfd_freq_max = 25e6; + tuning_constraints.rf_divider_range = uhd::range_t(1, 16); - UHD_LOGV(often) - << boost::format("SBX Intermediates: ref=%0.2f, outdiv=%f, fbdiv=%f") % (ref_freq*(1+int(D))/(R*(1+int(T)))) % double(RFdiv*2) % double(N + double(FRAC)/double(MOD)) << std::endl - << boost::format("SBX tune: R=%d, BS=%d, N=%d, FRAC=%d, MOD=%d, T=%d, D=%d, RFdiv=%d" - ) % R % BS % N % FRAC % MOD % T % D % RFdiv << std::endl - << boost::format("SBX Frequencies (MHz): REQ=%0.2f, ACT=%0.2f, VCO=%0.2f, PFD=%0.2f, BAND=%0.2f" - ) % (target_freq/1e6) % (actual_freq/1e6) % (vco_freq/1e6) % (pfd_freq/1e6) % (pfd_freq/BS/1e6) << std::endl; + double actual_freq; + adf435x_tuning_settings tuning_settings = _tune_adf435x_synth( + target_freq, self_base->get_iface()->get_clock_rate(unit), + tuning_constraints, actual_freq); //load the register values adf4350_regs_t regs; @@ -151,19 +87,25 @@ double sbx_xcvr::sbx_version3::set_lo_freq(dboard_iface::unit_t unit, double tar else regs.output_power = adf4350_regs_t::OUTPUT_POWER_5DBM; - regs.frac_12_bit = FRAC; - regs.int_16_bit = N; - regs.mod_12_bit = MOD; - regs.clock_divider_12_bit = std::max(1, int(std::ceil(400e-6*pfd_freq/MOD))); - regs.feedback_select = adf4350_regs_t::FEEDBACK_SELECT_DIVIDED; - regs.clock_div_mode = adf4350_regs_t::CLOCK_DIV_MODE_RESYNC_ENABLE; - regs.prescaler = prescaler; - regs.r_counter_10_bit = R; - regs.reference_divide_by_2 = T; - regs.reference_doubler = D; - regs.band_select_clock_div = BS; - UHD_ASSERT_THROW(rfdivsel_to_enum.has_key(RFdiv)); - regs.rf_divider_select = rfdivsel_to_enum[RFdiv]; + regs.frac_12_bit = tuning_settings.frac_12_bit; + regs.int_16_bit = tuning_settings.int_16_bit; + regs.mod_12_bit = tuning_settings.mod_12_bit; + regs.clock_divider_12_bit = tuning_settings.clock_divider_12_bit; + regs.feedback_select = tuning_settings.feedback_after_divider ? + adf4350_regs_t::FEEDBACK_SELECT_DIVIDED : + adf4350_regs_t::FEEDBACK_SELECT_FUNDAMENTAL; + regs.clock_div_mode = adf4350_regs_t::CLOCK_DIV_MODE_RESYNC_ENABLE; + regs.prescaler = prescaler; + regs.r_counter_10_bit = tuning_settings.r_counter_10_bit; + regs.reference_divide_by_2 = tuning_settings.r_divide_by_2_en ? + adf4350_regs_t::REFERENCE_DIVIDE_BY_2_ENABLED : + adf4350_regs_t::REFERENCE_DIVIDE_BY_2_DISABLED; + regs.reference_doubler = tuning_settings.r_doubler_en ? + adf4350_regs_t::REFERENCE_DOUBLER_ENABLED : + adf4350_regs_t::REFERENCE_DOUBLER_DISABLED; + regs.band_select_clock_div = tuning_settings.band_select_clock_div; + UHD_ASSERT_THROW(rfdivsel_to_enum.has_key(tuning_settings.rf_divider)); + regs.rf_divider_select = rfdivsel_to_enum[tuning_settings.rf_divider]; //reset the N and R counter regs.counter_reset = adf4350_regs_t::COUNTER_RESET_ENABLED; diff --git a/host/lib/usrp/dboard/db_sbx_version4.cpp b/host/lib/usrp/dboard/db_sbx_version4.cpp index 27fd68b05..8d95b0655 100644 --- a/host/lib/usrp/dboard/db_sbx_version4.cpp +++ b/host/lib/usrp/dboard/db_sbx_version4.cpp @@ -66,85 +66,21 @@ double sbx_xcvr::sbx_version4::set_lo_freq(dboard_iface::unit_t unit, double tar (64, adf4351_regs_t::RF_DIVIDER_SELECT_DIV64) ; - double actual_freq, pfd_freq; - double ref_freq = self_base->get_iface()->get_clock_rate(unit); - int R=0, BS=0, N=0, FRAC=0, MOD=0; - int RFdiv = 1; - adf4351_regs_t::reference_divide_by_2_t T = adf4351_regs_t::REFERENCE_DIVIDE_BY_2_DISABLED; - adf4351_regs_t::reference_doubler_t D = adf4351_regs_t::REFERENCE_DOUBLER_DISABLED; - - //Reference doubler for 50% duty cycle - // if ref_freq < 12.5MHz enable regs.reference_divide_by_2 - if(ref_freq <= 12.5e6) D = adf4351_regs_t::REFERENCE_DOUBLER_ENABLED; - - //increase RF divider until acceptable VCO frequency - double vco_freq = target_freq; - while (vco_freq < 2.2e9) { - vco_freq *= 2; - RFdiv *= 2; - } - //use 8/9 prescaler for vco_freq > 3 GHz (pg.18 prescaler) - adf4351_regs_t::prescaler_t prescaler = target_freq > 3e9 ? adf4351_regs_t::PRESCALER_8_9 : adf4351_regs_t::PRESCALER_4_5; - - /* - * The goal here is to loop though possible R dividers, - * band select clock dividers, N (int) dividers, and FRAC - * (frac) dividers. - * - * Calculate the N and F dividers for each set of values. - * The loop exits when it meets all of the constraints. - * The resulting loop values are loaded into the registers. - * - * from pg.21 - * - * f_pfd = f_ref*(1+D)/(R*(1+T)) - * f_vco = (N + (FRAC/MOD))*f_pfd - * N = f_vco/f_pfd - FRAC/MOD = f_vco*((R*(T+1))/(f_ref*(1+D))) - FRAC/MOD - * f_rf = f_vco/RFdiv) - * f_actual = f_rf/2 - */ - for(R = 1; R <= 1023; R+=1){ - //PFD input frequency = f_ref/R ... ignoring Reference doubler/divide-by-2 (D & T) - pfd_freq = ref_freq*(1+D)/(R*(1+T)); - - //keep the PFD frequency at or below 25MHz (Loop Filter Bandwidth) - if (pfd_freq > 25e6) continue; - - //ignore fractional part of tuning - N = int(std::floor(vco_freq/pfd_freq)); - - //keep N > minimum int divider requirement - if (N < prescaler_to_min_int_div[prescaler]) continue; - - for(BS=1; BS <= 255; BS+=1){ - //keep the band select frequency at or below 100KHz - //constraint on band select clock - if (pfd_freq/BS > 100e3) continue; - goto done_loop; - } - } done_loop: - - //Fractional-N calculation - MOD = 4095; //max fractional accuracy - FRAC = int((target_freq/pfd_freq - N)*MOD); - - //Reference divide-by-2 for 50% duty cycle - // if R even, move one divide by 2 to to regs.reference_divide_by_2 - if(R % 2 == 0){ - T = adf4351_regs_t::REFERENCE_DIVIDE_BY_2_ENABLED; - R /= 2; - } + adf4351_regs_t::prescaler_t prescaler = target_freq > 3.6e9 ? adf4351_regs_t::PRESCALER_8_9 : adf4351_regs_t::PRESCALER_4_5; - //actual frequency calculation - actual_freq = double((N + (double(FRAC)/double(MOD)))*ref_freq*(1+int(D))/(R*(1+int(T)))); + adf435x_tuning_constraints tuning_constraints; + tuning_constraints.force_frac0 = false; + tuning_constraints.band_sel_freq_max = 100e3; + tuning_constraints.ref_doubler_threshold = 12.5e6; + tuning_constraints.int_range = uhd::range_t(prescaler_to_min_int_div[prescaler], 4095); //INT is a 12-bit field + tuning_constraints.pfd_freq_max = 25e6; + tuning_constraints.rf_divider_range = uhd::range_t(1, 64); - UHD_LOGV(often) - << boost::format("SBX Intermediates: ref=%0.2f, outdiv=%f, fbdiv=%f") % (ref_freq*(1+int(D))/(R*(1+int(T)))) % double(RFdiv*2) % double(N + double(FRAC)/double(MOD)) << std::endl - << boost::format("SBX tune: R=%d, BS=%d, N=%d, FRAC=%d, MOD=%d, T=%d, D=%d, RFdiv=%d" - ) % R % BS % N % FRAC % MOD % T % D % RFdiv << std::endl - << boost::format("SBX Frequencies (MHz): REQ=%0.2f, ACT=%0.2f, VCO=%0.2f, PFD=%0.2f, BAND=%0.2f" - ) % (target_freq/1e6) % (actual_freq/1e6) % (vco_freq/1e6) % (pfd_freq/1e6) % (pfd_freq/BS/1e6) << std::endl; + double actual_freq; + adf435x_tuning_settings tuning_settings = _tune_adf435x_synth( + target_freq, self_base->get_iface()->get_clock_rate(unit), + tuning_constraints, actual_freq); //load the register values adf4351_regs_t regs; @@ -154,19 +90,25 @@ double sbx_xcvr::sbx_version4::set_lo_freq(dboard_iface::unit_t unit, double tar else regs.output_power = adf4351_regs_t::OUTPUT_POWER_5DBM; - regs.frac_12_bit = FRAC; - regs.int_16_bit = N; - regs.mod_12_bit = MOD; - regs.clock_divider_12_bit = std::max(1, int(std::ceil(400e-6*pfd_freq/MOD))); - regs.feedback_select = adf4351_regs_t::FEEDBACK_SELECT_DIVIDED; - regs.clock_div_mode = adf4351_regs_t::CLOCK_DIV_MODE_RESYNC_ENABLE; - regs.prescaler = prescaler; - regs.r_counter_10_bit = R; - regs.reference_divide_by_2 = T; - regs.reference_doubler = D; - regs.band_select_clock_div = BS; - UHD_ASSERT_THROW(rfdivsel_to_enum.has_key(RFdiv)); - regs.rf_divider_select = rfdivsel_to_enum[RFdiv]; + regs.frac_12_bit = tuning_settings.frac_12_bit; + regs.int_16_bit = tuning_settings.int_16_bit; + regs.mod_12_bit = tuning_settings.mod_12_bit; + regs.clock_divider_12_bit = tuning_settings.clock_divider_12_bit; + regs.feedback_select = tuning_settings.feedback_after_divider ? + adf4351_regs_t::FEEDBACK_SELECT_DIVIDED : + adf4351_regs_t::FEEDBACK_SELECT_FUNDAMENTAL; + regs.clock_div_mode = adf4351_regs_t::CLOCK_DIV_MODE_RESYNC_ENABLE; + regs.prescaler = prescaler; + regs.r_counter_10_bit = tuning_settings.r_counter_10_bit; + regs.reference_divide_by_2 = tuning_settings.r_divide_by_2_en ? + adf4351_regs_t::REFERENCE_DIVIDE_BY_2_ENABLED : + adf4351_regs_t::REFERENCE_DIVIDE_BY_2_DISABLED; + regs.reference_doubler = tuning_settings.r_doubler_en ? + adf4351_regs_t::REFERENCE_DOUBLER_ENABLED : + adf4351_regs_t::REFERENCE_DOUBLER_DISABLED; + regs.band_select_clock_div = tuning_settings.band_select_clock_div; + UHD_ASSERT_THROW(rfdivsel_to_enum.has_key(tuning_settings.rf_divider)); + regs.rf_divider_select = rfdivsel_to_enum[tuning_settings.rf_divider]; //reset the N and R counter regs.counter_reset = adf4351_regs_t::COUNTER_RESET_ENABLED; diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index 253ac1d6f..625926f36 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -258,12 +258,14 @@ usrp1_impl::usrp1_impl(const device_addr_t &device_addr){ _tree->create<std::string>(rx_codec_path / "name").set("ad9522"); _tree->create<meta_range_t>(rx_codec_path / "gains/pga/range").set(usrp1_codec_ctrl::rx_pga_gain_range); _tree->create<double>(rx_codec_path / "gains/pga/value") - .coerce(boost::bind(&usrp1_impl::update_rx_codec_gain, this, db, _1)); + .coerce(boost::bind(&usrp1_impl::update_rx_codec_gain, this, db, _1)) + .set(0.0); _tree->create<std::string>(tx_codec_path / "name").set("ad9522"); _tree->create<meta_range_t>(tx_codec_path / "gains/pga/range").set(usrp1_codec_ctrl::tx_pga_gain_range); _tree->create<double>(tx_codec_path / "gains/pga/value") .subscribe(boost::bind(&usrp1_codec_ctrl::set_tx_pga_gain, _dbc[db].codec, _1)) - .publish(boost::bind(&usrp1_codec_ctrl::get_tx_pga_gain, _dbc[db].codec)); + .publish(boost::bind(&usrp1_codec_ctrl::get_tx_pga_gain, _dbc[db].codec)) + .set(0.0); } //////////////////////////////////////////////////////////////////// @@ -407,7 +409,7 @@ usrp1_impl::usrp1_impl(const device_addr_t &device_addr){ _tree->access<subdev_spec_t>(mb_path / "rx_subdev_spec").set(_rx_subdev_spec); if (_tree->list(mb_path / "tx_dsps").size() > 0) _tree->access<subdev_spec_t>(mb_path / "tx_subdev_spec").set(_tx_subdev_spec); - + } usrp1_impl::~usrp1_impl(void){ diff --git a/host/lib/utils/paths.cpp b/host/lib/utils/paths.cpp index 53055314b..25cade693 100644 --- a/host/lib/utils/paths.cpp +++ b/host/lib/utils/paths.cpp @@ -34,8 +34,19 @@ namespace fs = boost::filesystem; /*********************************************************************** + * Get a list of paths for an environment variable + **********************************************************************/ +static std::string get_env_var(const std::string &var_name, const std::string &def_val = ""){ + const char *var_value_ptr = std::getenv(var_name.c_str()); + return (var_value_ptr == NULL)? def_val : var_value_ptr; +} + +static std::vector<fs::path> get_env_paths(const std::string &var_name){ + +/*********************************************************************** * Determine the paths separator **********************************************************************/ + #ifdef UHD_PLATFORM_WIN32 static const std::string env_path_sep = ";"; #else @@ -46,16 +57,6 @@ namespace fs = boost::filesystem; boost::tokenizer<boost::char_separator<char> > \ (inp, boost::char_separator<char>(env_path_sep.c_str())) -/*********************************************************************** - * Get a list of paths for an environment variable - **********************************************************************/ -static std::string get_env_var(const std::string &var_name, const std::string &def_val = ""){ - const char *var_value_ptr = std::getenv(var_name.c_str()); - return (var_value_ptr == NULL)? def_val : var_value_ptr; -} - -static std::vector<fs::path> get_env_paths(const std::string &var_name){ - std::string var_value = get_env_var(var_name); //convert to filesystem path, filter blank paths @@ -85,6 +86,7 @@ std::vector<fs::path> get_image_paths(void){ std::vector<fs::path> get_module_paths(void){ std::vector<fs::path> paths = get_env_paths("UHD_MODULE_PATH"); paths.push_back(fs::path(uhd::get_pkg_path()) / UHD_LIB_DIR / "uhd" / "modules"); + paths.push_back(fs::path(uhd::get_pkg_path()) / "share" / "uhd" / "modules"); return paths; } diff --git a/host/utils/uhd_images_downloader.py.in b/host/utils/uhd_images_downloader.py.in index e7fc9e8a5..bb082190c 100644 --- a/host/utils/uhd_images_downloader.py.in +++ b/host/utils/uhd_images_downloader.py.in @@ -44,13 +44,25 @@ class temp_dir(): self.name = tempfile.mkdtemp() return self.name def __exit__(self, type, value, traceback): - os.removedirs(self.name) + try: + shutil.rmtree(self.name) + except OSError,e: + #Utility should have already detected this, but this is for safety + print str(e) + raise Exception("Could not install images! Make sure you have write permissions.") if __name__ == "__main__": + print + if os.environ.get("UHD_IMAGES_DIR") != None and os.environ.get("UHD_IMAGES_DIR") != "": + default_images_dir = os.environ.get("UHD_IMAGES_DIR") + print "UHD_IMAGES_DIR environment variable is set. Default install location: %s" % default_images_dir + else: + default_images_dir = "@CMAKE_INSTALL_PREFIX@/share/uhd/images" + #Command line options parser = OptionParser() - parser.add_option("--install-location", type="string", default="", help="Set custom install location for images") + parser.add_option("--install-location", type="string", default=default_images_dir, help="Set custom install location for images") parser.add_option("--buffer-size", type="int", default=8192, help="Set download buffer size, [default=%default]",) (options, args) = parser.parse_args() @@ -59,17 +71,27 @@ if __name__ == "__main__": images_zip_md5sum = "@UHD_IMAGES_MD5SUM@" filename = images_src.split("/")[-1] + #Use this directory with relative paths + current_directory = os.getcwd() + with temp_dir() as dirname: os.chdir(dirname) - #Configuring image destination - if options.install_location != "": + if os.path.isabs(options.install_location): + #Custom absolute path given images_dir = options.install_location - elif os.environ.get("UHD_IMAGES_DIR") != "" and os.environ.get("UHD_IMAGES_DIR") != None: - images_dir = os.environ.get("UHD_IMAGES_DIR") else: - images_dir = "@CMAKE_INSTALL_PREFIX@/share/uhd/images" - + #Custom relative path given, so construct absolute path + images_dir = os.path.abspath(os.path.join(current_directory, options.install_location)) + + #Before doing anything, check for write permissions in parent directory + parent_directory = os.path.dirname(images_dir) + if os.access(parent_directory, os.W_OK): + print "Downloading images to: %s" % images_dir + else: + print "You do not have write permissions at the install location!" + sys.exit(1) + opener = urllib2.build_opener() opener.add_headers = [('User-Agent', 'UHD Images Downloader')] u = opener.open(images_src) @@ -101,32 +123,37 @@ if __name__ == "__main__": if images_zip_md5sum != downloaded_zip_md5sum: print "\nMD5 checksum does not match!" print "Expected %s, got %s" % (images_zip_md5sum, downloaded_zip_md5sum) + print "Images did not install. If problem persists, please contact support@ettus.com." os.remove(filename) os.chdir("/".join(images_dir.split("/")[:-1])) + sys.exit(1) else: + temp_path = "tempdir" + #Extracting contents of zip file - if os.path.exists("tempdir"): - shutil.rmtree("tempdir") - os.mkdir("tempdir") + if os.path.exists(temp_path): + shutil.rmtree(temp_path) + os.mkdir(temp_path) images_zip = zipfile.ZipFile(filename) - images_zip.extractall("tempdir") + images_zip.extractall(temp_path) #Removing images currently in images_dir if os.path.exists(images_dir): try: shutil.rmtree(images_dir) - except: - sys.stderr.write("\nMake sure you have write permissions in the images directory.\n") - sys.exit(0) + except OSError,e: + print str(e) + print "Make sure you have write permissions in the images directory." + sys.exit(1) #Copying downloaded images into images_dir - shutil.copytree("tempdir/%s/share/uhd/images" % filename[:-4],images_dir) + shutil.copytree(os.path.join(temp_path, os.path.splitext(filename)[0], 'share', 'uhd', 'images'), images_dir) #Removing tempdir and zip file - shutil.rmtree("tempdir") + shutil.rmtree(temp_path) images_zip.close() os.remove(filename) os.chdir(images_dir) - print "\nImages successfully installed to: %s" % images_dir + print "\n\nImages successfully installed!" diff --git a/host/utils/usrp_burn_mb_eeprom.cpp b/host/utils/usrp_burn_mb_eeprom.cpp index 1b13fb615..ce0879c8e 100644 --- a/host/utils/usrp_burn_mb_eeprom.cpp +++ b/host/utils/usrp_burn_mb_eeprom.cpp @@ -1,5 +1,5 @@ // -// Copyright 2010 Ettus Research LLC +// Copyright 2010,2013 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 @@ -19,9 +19,11 @@ #include <uhd/device.hpp> #include <uhd/property_tree.hpp> #include <uhd/usrp/mboard_eeprom.hpp> +#include <boost/algorithm/string.hpp> #include <boost/program_options.hpp> #include <boost/format.hpp> #include <iostream> +#include <vector> namespace po = boost::program_options; @@ -32,8 +34,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ desc.add_options() ("help", "help message") ("args", po::value<std::string>(&args)->default_value(""), "device address args [default = \"\"]") - ("key", po::value<std::string>(&key), "the indentifier for a value in EEPROM") - ("val", po::value<std::string>(&val), "the new value to set, omit for readback") + ("key", po::value<std::string>(&key), "identifiers for new values in EEPROM, separate multiple by \",\"") + ("val", po::value<std::string>(&val), "the new values to set, omit for readback, separate multiple by \",\"") ; po::variables_map vm; @@ -55,20 +57,35 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ uhd::property_tree::sptr tree = dev->get_tree(); std::cout << std::endl; - if (true /*always readback*/){ - std::cout << "Fetching current settings from EEPROM..." << std::endl; - uhd::usrp::mboard_eeprom_t mb_eeprom = tree->access<uhd::usrp::mboard_eeprom_t>("/mboards/0/eeprom").get(); - if (not mb_eeprom.has_key(key)){ - std::cerr << boost::format("Cannot find value for EEPROM[%s]") % key << std::endl; + //remove whitespace, split arguments and values + boost::algorithm::erase_all(key, " "); + boost::algorithm::erase_all(val, " "); + + std::vector<std::string> keys_vec, vals_vec; + boost::split(keys_vec, key, boost::is_any_of("\"',")); + boost::split(vals_vec, val, boost::is_any_of("\"',")); + + if((keys_vec.size() != vals_vec.size()) and val != "") { + //If zero values are given, then user just wants values read to them + throw std::runtime_error("Number of keys must match number of values!"); + } + + std::cout << "Fetching current settings from EEPROM..." << std::endl; + uhd::usrp::mboard_eeprom_t mb_eeprom = tree->access<uhd::usrp::mboard_eeprom_t>("/mboards/0/eeprom").get(); + for(size_t i = 0; i < keys_vec.size(); i++){ + if (not mb_eeprom.has_key(keys_vec[i])){ + std::cerr << boost::format("Cannot find value for EEPROM[%s]") % keys_vec[i] << std::endl; return EXIT_FAILURE; } - std::cout << boost::format(" EEPROM [\"%s\"] is \"%s\"") % key % mb_eeprom[key] << std::endl; - std::cout << std::endl; + std::cout << boost::format(" EEPROM [\"%s\"] is \"%s\"") % keys_vec[i] % mb_eeprom[keys_vec[i]] << std::endl; } + std::cout << std::endl; if (vm.count("val")){ - uhd::usrp::mboard_eeprom_t mb_eeprom; mb_eeprom[key] = val; - std::cout << boost::format("Setting EEPROM [\"%s\"] to \"%s\"...") % key % val << std::endl; - tree->access<uhd::usrp::mboard_eeprom_t>("/mboards/0/eeprom").set(mb_eeprom); + for(size_t i = 0; i < vals_vec.size(); i++){ + uhd::usrp::mboard_eeprom_t mb_eeprom; mb_eeprom[keys_vec[i]] = vals_vec[i]; + std::cout << boost::format("Setting EEPROM [\"%s\"] to \"%s\"...") % keys_vec[i] % vals_vec[i] << std::endl; + tree->access<uhd::usrp::mboard_eeprom_t>("/mboards/0/eeprom").set(mb_eeprom); + } std::cout << "Power-cycle the USRP device for the changes to take effect." << std::endl; std::cout << std::endl; } |