From a7c230cb1f97b452da027d5baa71891f2066d430 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 28 Apr 2010 16:35:22 -0700 Subject: Added reload flag to the stream cmd. This reloads the last command to handle continuous streaming in hardware. Moved rx control register setup and stream command issuing to the host. --- host/lib/usrp/usrp2/dsp_impl.cpp | 3 -- host/lib/usrp/usrp2/fw_common.h | 14 +-------- host/lib/usrp/usrp2/io_impl.cpp | 22 ++++++++++---- host/lib/usrp/usrp2/mboard_impl.cpp | 59 ++++++++++++++++--------------------- host/lib/usrp/usrp2/usrp2_regs.hpp | 21 +++++++++++++ 5 files changed, 63 insertions(+), 56 deletions(-) (limited to 'host/lib') diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index 84314a656..bd61ac376 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -77,9 +77,6 @@ void usrp2_impl::init_ddc_config(void){ _ddc_decim = default_decim; _ddc_freq = 0; update_ddc_config(); - - //initial command that kills streaming (in case if was left on) - issue_ddc_stream_cmd(stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS); } void usrp2_impl::update_ddc_config(void){ diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index e80001ff2..f28013cf6 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -34,7 +34,7 @@ extern "C" { //defines the protocol version in this shared header //increment this value when the protocol is changed -#define USRP2_PROTO_VERSION 2 +#define USRP2_PROTO_VERSION 3 //used to differentiate control packets over data port #define USRP2_INVALID_VRT_HEADER 0 @@ -70,9 +70,6 @@ typedef enum{ USRP2_CTRL_ID_WRITE_THESE_I2C_VALUES_BRO = 'h', USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE = 'H', - USRP2_CTRL_ID_SEND_STREAM_COMMAND_FOR_ME_BRO = '{', - USRP2_CTRL_ID_GOT_THAT_STREAM_COMMAND_DUDE = '}', - USRP2_CTRL_ID_POKE_THIS_REGISTER_FOR_ME_BRO = 'p', USRP2_CTRL_ID_OMG_POKED_REGISTER_SO_BAD_DUDE = 'P', @@ -113,15 +110,6 @@ typedef struct{ _SINS_ uint8_t bytes; _SINS_ uint8_t data[sizeof(_SINS_ uint32_t)]; } i2c_args; - struct { - _SINS_ uint8_t now; //stream now? - _SINS_ uint8_t continuous; //auto-reload commmands? - _SINS_ uint8_t chain; - _SINS_ uint8_t _pad[1]; - _SINS_ uint32_t secs; - _SINS_ uint32_t ticks; - _SINS_ uint32_t num_samps; - } stream_cmd; struct { _SINS_ uint32_t addr; _SINS_ uint32_t data; diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 367a1d9fb..a2e99c824 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -16,6 +16,7 @@ // #include "usrp2_impl.hpp" +#include "usrp2_regs.hpp" #include #include #include //htonl and ntohl @@ -39,14 +40,23 @@ void usrp2_impl::io_init(void){ _rx_copy_buff = asio::buffer("", 0); //send a small data packet so the usrp2 knows the udp source port - //and the maximum number of lines (32 bit words) per packet managed_send_buffer::sptr send_buff = _data_transport->get_send_buff(); - boost::uint32_t data[2] = { - htonl(USRP2_INVALID_VRT_HEADER), - htonl(_max_rx_samples_per_packet) - }; - memcpy(send_buff->cast(), data, sizeof(data)); + boost::uint32_t data = htonl(USRP2_INVALID_VRT_HEADER); + memcpy(send_buff->cast(), &data, sizeof(data)); send_buff->done(sizeof(data)); + + //setup RX DSP regs + _iface->poke32(FR_RX_CTRL_NSAMPS_PER_PKT, _max_rx_samples_per_packet); + _iface->poke32(FR_RX_CTRL_NCHANNELS, 1); + _iface->poke32(FR_RX_CTRL_CLEAR_OVERRUN, 1); //reset + _iface->poke32(FR_RX_CTRL_VRT_HEADER, 0 + | (0x1 << 28) //if data with stream id + | (0x1 << 26) //has trailer + | (0x3 << 22) //integer time other + | (0x1 << 20) //fractional time sample count + ); + _iface->poke32(FR_RX_CTRL_VRT_STREAM_ID, 0); + _iface->poke32(FR_RX_CTRL_VRT_TRAILER, 0); } /*********************************************************************** diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 36bef4f25..48aeb2a62 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -119,40 +119,31 @@ void usrp2_impl::set_time_spec(const time_spec_t &time_spec, bool now){ } void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ - //setup the out data - usrp2_ctrl_data_t out_data; - out_data.id = htonl(USRP2_CTRL_ID_SEND_STREAM_COMMAND_FOR_ME_BRO); - out_data.data.stream_cmd.now = (stream_cmd.stream_now)? 1 : 0; - out_data.data.stream_cmd.secs = htonl(stream_cmd.time_spec.secs); - out_data.data.stream_cmd.ticks = htonl(stream_cmd.time_spec.get_ticks(get_master_clock_freq())); - - //set these to defaults, then change in the switch statement - out_data.data.stream_cmd.continuous = 0; - out_data.data.stream_cmd.chain = 0; - out_data.data.stream_cmd.num_samps = htonl(stream_cmd.num_samps); - - //setup chain, num samps, and continuous below - switch(stream_cmd.stream_mode){ - case stream_cmd_t::STREAM_MODE_START_CONTINUOUS: - out_data.data.stream_cmd.continuous = 1; - break; - - case stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS: - out_data.data.stream_cmd.num_samps = htonl(0); - break; - - case stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE: - //all set by defaults above - break; - - case stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE: - out_data.data.stream_cmd.chain = 1; - break; - } - - //send and recv - usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data); - UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_GOT_THAT_STREAM_COMMAND_DUDE); + UHD_ASSERT_THROW(stream_cmd.num_samps <= FR_RX_CTRL_MAX_SAMPS_PER_CMD); + + //setup the mode to instruction flags + typedef boost::tuple inst_t; + static const uhd::dict mode_to_inst = boost::assign::map_list_of + //reload, chain, samps + (stream_cmd_t::STREAM_MODE_START_CONTINUOUS, inst_t(true, true, false)) + (stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS, inst_t(false, false, false)) + (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_DONE, inst_t(false, false, true)) + (stream_cmd_t::STREAM_MODE_NUM_SAMPS_AND_MORE, inst_t(false, true, true)) + ; + + //setup the instruction flag values + bool inst_reload, inst_chain, inst_samps; + boost::tie(inst_reload, inst_chain, inst_samps) = mode_to_inst[stream_cmd.stream_mode]; + + //issue the stream command + _iface->poke32(FR_RX_CTRL_STREAM_CMD, FR_RX_CTRL_MAKE_CMD( + (inst_samps)? stream_cmd.num_samps : ((inst_chain)? _max_rx_samples_per_packet : 1), + (stream_cmd.stream_now)? 1 : 0, + (inst_chain)? 1 : 0, + (inst_reload)? 1 : 0 + )); + _iface->poke32(FR_RX_CTRL_TIME_SECS, stream_cmd.time_spec.secs); + _iface->poke32(FR_RX_CTRL_TIME_TICKS, stream_cmd.time_spec.get_ticks(get_master_clock_freq())); } /*********************************************************************** diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp index 0e2a18756..67a342217 100644 --- a/host/lib/usrp/usrp2/usrp2_regs.hpp +++ b/host/lib/usrp/usrp2/usrp2_regs.hpp @@ -207,4 +207,25 @@ #define FR_ATR_FULL_TXSIDE FR_ATR_BASE + 12 #define FR_ATR_FULL_RXSIDE FR_ATR_BASE + 14 +/////////////////////////////////////////////////// +// ATR Controller, Slave 11 +/////////////////////////////////////////////////// +// The following 3 are logically a single command register. +// They are clocked into the underlying fifo when time_ticks is written. +#define FR_RX_CTRL_STREAM_CMD _SR_ADDR(SR_RX_CTRL + 0) // {now, chain, num_samples(30) +#define FR_RX_CTRL_TIME_SECS _SR_ADDR(SR_RX_CTRL + 1) +#define FR_RX_CTRL_TIME_TICKS _SR_ADDR(SR_RX_CTRL + 2) + +#define FR_RX_CTRL_CLEAR_OVERRUN _SR_ADDR(SR_RX_CTRL + 3) // write anything to clear overrun +#define FR_RX_CTRL_VRT_HEADER _SR_ADDR(SR_RX_CTRL + 4) // word 0 of packet. FPGA fills in packet counter +#define FR_RX_CTRL_VRT_STREAM_ID _SR_ADDR(SR_RX_CTRL + 5) // word 1 of packet. +#define FR_RX_CTRL_VRT_TRAILER _SR_ADDR(SR_RX_CTRL + 6) +#define FR_RX_CTRL_NSAMPS_PER_PKT _SR_ADDR(SR_RX_CTRL + 7) +#define FR_RX_CTRL_NCHANNELS _SR_ADDR(SR_RX_CTRL + 8) // 1 in basic case, up to 4 for vector sources + +//helpful macros for dealing with stream cmd +#define FR_RX_CTRL_MAX_SAMPS_PER_CMD 0x1fffffff +#define FR_RX_CTRL_MAKE_CMD(nsamples, now, chain, reload) \ + ((((now) & 0x1) << 31) | (((chain) & 0x1) << 30) | (((reload) & 0x1) << 29) | ((nsamples) & 0x1fffffff)) + #endif /* INCLUDED_USRP2_REGS_HPP */ -- cgit v1.2.3 From 30bd666e306cb8f8c947c6ba99a76f7c49484597 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 28 Apr 2010 17:38:22 -0700 Subject: Moved some misc setting registers into host. --- firmware/microblaze/lib/u2_init.c | 10 ---------- host/lib/usrp/usrp2/mboard_impl.cpp | 13 ++++++++++--- host/lib/usrp/usrp2/usrp2_regs.hpp | 20 ++++++++++++++++++-- 3 files changed, 28 insertions(+), 15 deletions(-) (limited to 'host/lib') diff --git a/firmware/microblaze/lib/u2_init.c b/firmware/microblaze/lib/u2_init.c index b4fbb9e88..6809101c0 100644 --- a/firmware/microblaze/lib/u2_init.c +++ b/firmware/microblaze/lib/u2_init.c @@ -46,8 +46,6 @@ get_hw_rev(void) bool u2_init(void) { - dsp_rx_regs->gpio_stream_enable = 0; // I, Q LSBs come from DSP - hal_io_init(); // init spi, so that we can switch over to the high-speed clock @@ -60,14 +58,6 @@ u2_init(void) // set up the default clocks clocks_init(); - // clocks_enable_test_clk(true,1); - - // Enable ADCs - output_regs->adc_ctrl = ADC_CTRL_ON; - - // Set up serdes - output_regs->serdes_ctrl = (SERDES_ENABLE | SERDES_RXEN); - pic_init(); // progammable interrupt controller bp_init(); // buffer pool diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 48aeb2a62..2c8fd2df4 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -63,6 +63,13 @@ void usrp2_impl::mboard_init(void){ boost::uint16_t data = ad9777_regs.get_write_reg(addr); _iface->transact_spi(SPI_SS_AD9777, spi_config_t::EDGE_RISE, data, 16, false /*no rb*/); } + + //enable ADCs + _iface->poke32(FR_MISC_CTRL_ADC, FRF_MISC_CTRL_ADC_ON); + + //set up serdes + _iface->poke32(FR_MISC_CTRL_SERDES, FRF_MISC_CTRL_SERDES_ENABLE | FRF_MISC_CTRL_SERDES_RXEN); + } void usrp2_impl::init_clock_config(void){ @@ -97,9 +104,9 @@ void usrp2_impl::update_clock_config(void){ //clock source ref 10mhz switch(_clock_config.ref_source){ - case clock_config_t::REF_INT : _iface->poke32(FR_CLOCK_CONTROL, 0x10); break; - case clock_config_t::REF_SMA : _iface->poke32(FR_CLOCK_CONTROL, 0x1C); break; - case clock_config_t::REF_MIMO: _iface->poke32(FR_CLOCK_CONTROL, 0x15); break; + case clock_config_t::REF_INT : _iface->poke32(FR_MISC_CTRL_CLOCK, 0x10); break; + case clock_config_t::REF_SMA : _iface->poke32(FR_MISC_CTRL_CLOCK, 0x1C); break; + case clock_config_t::REF_MIMO: _iface->poke32(FR_MISC_CTRL_CLOCK, 0x15); break; default: throw std::runtime_error("usrp2: unhandled clock configuration reference source"); } diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp index 67a342217..feeccaa34 100644 --- a/host/lib/usrp/usrp2/usrp2_regs.hpp +++ b/host/lib/usrp/usrp2/usrp2_regs.hpp @@ -64,7 +64,23 @@ ///////////////////////////////////////////////// // Misc Control //////////////////////////////////////////////// -#define FR_CLOCK_CONTROL _SR_ADDR(0) +#define FR_MISC_CTRL_CLOCK _SR_ADDR(0) +#define FR_MISC_CTRL_SERDES _SR_ADDR(1) +#define FR_MISC_CTRL_ADC _SR_ADDR(2) +#define FR_MISC_CTRL_LEDS _SR_ADDR(3) +#define FR_MISC_CTRL_PHY _SR_ADDR(4) // LSB is reset line to eth phy +#define FR_MISC_CTRL_DBG_MUX _SR_ADDR(5) +#define FR_MISC_CTRL_RAM_PAGE _SR_ADDR(6) // FIXME should go somewhere else... +#define FR_MISC_CTRL_FLUSH_ICACHE _SR_ADDR(7) // Flush the icache +#define FR_MISC_CTRL_LED_SRC _SR_ADDR(8) // HW or SW control for LEDs + +#define FRF_MISC_CTRL_SERDES_ENABLE 8 +#define FRF_MISC_CTRL_SERDES_PRBSEN 4 +#define FRF_MISC_CTRL_SERDES_LOOPEN 2 +#define FRF_MISC_CTRL_SERDES_RXEN 1 + +#define FRF_MISC_CTRL_ADC_ON 0x0F +#define FRF_MISC_CTRL_ADC_OFF 0x00 ///////////////////////////////////////////////// // VITA49 64 bit time (write only) @@ -208,7 +224,7 @@ #define FR_ATR_FULL_RXSIDE FR_ATR_BASE + 14 /////////////////////////////////////////////////// -// ATR Controller, Slave 11 +// VITA RX CTRL regs /////////////////////////////////////////////////// // The following 3 are logically a single command register. // They are clocked into the underlying fifo when time_ticks is written. -- cgit v1.2.3 From 9c7c178f70f8a78dc638d5f4301407893351b4fd Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 10 May 2010 14:17:25 -0700 Subject: added save state for ic regs map common --- host/lib/ic_reg_maps/common.py | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) (limited to 'host/lib') diff --git a/host/lib/ic_reg_maps/common.py b/host/lib/ic_reg_maps/common.py index 4aa1ef35e..e27c2816d 100644 --- a/host/lib/ic_reg_maps/common.py +++ b/host/lib/ic_reg_maps/common.py @@ -29,30 +29,59 @@ COMMON_TMPL = """\ \#ifndef INCLUDED_$(name.upper())_HPP \#define INCLUDED_$(name.upper())_HPP +\#include \#include +\#include +\#include -struct $(name)_t{ - +class $(name)_t{ +public: #for $reg in $regs - #if $reg.get_enums() + #if $reg.get_enums() enum $reg.get_type(){ #for $i, $enum in enumerate($reg.get_enums()) #set $end_comma = ',' if $i < len($reg.get_enums())-1 else '' $(reg.get_name().upper())_$(enum[0].upper()) = $enum[1]$end_comma #end for }; - #end if + #end if $reg.get_type() $reg.get_name(); #end for $(name)_t(void){ - #for $reg in $regs + _state = NULL; + #for $reg in $regs $reg.get_name() = $reg.get_default(); - #end for + #end for + } + + ~$(name)_t(void){ + delete _state; } $body + void save_state(void){ + if (_state == NULL) _state = new $(name)_t(); + #for $reg in $regs + _state->$reg.get_name() = this->$reg.get_name(); + #end for + } + + template std::set get_changed_addrs(void){ + if (_state == NULL) throw std::runtime_error("no saved state"); + //check each register for changes + std::set addrs; + #for $reg in $regs + if(_state->$reg.get_name() != this->$reg.get_name()){ + addrs.insert($reg.get_addr()); + } + #end for + return addrs; + } + +private: + $(name)_t *_state; }; \#endif /* INCLUDED_$(name.upper())_HPP */ -- cgit v1.2.3 From bf7ef6aeb502839797894cac4d7518029a0d04c4 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 10 May 2010 15:14:48 -0700 Subject: Moved adc and dac control into codec control source file. The codec control powers down the chips on destruction. --- host/lib/usrp/usrp2/CMakeLists.txt | 3 +- host/lib/usrp/usrp2/clock_control.cpp | 157 ---------------------------------- host/lib/usrp/usrp2/clock_control.hpp | 60 ------------- host/lib/usrp/usrp2/clock_ctrl.cpp | 155 +++++++++++++++++++++++++++++++++ host/lib/usrp/usrp2/clock_ctrl.hpp | 60 +++++++++++++ host/lib/usrp/usrp2/codec_ctrl.cpp | 91 ++++++++++++++++++++ host/lib/usrp/usrp2/codec_ctrl.hpp | 38 ++++++++ host/lib/usrp/usrp2/dboard_iface.cpp | 18 ++-- host/lib/usrp/usrp2/dboard_impl.cpp | 2 +- host/lib/usrp/usrp2/mboard_impl.cpp | 32 +------ host/lib/usrp/usrp2/usrp2_impl.cpp | 2 + host/lib/usrp/usrp2/usrp2_impl.hpp | 8 +- 12 files changed, 364 insertions(+), 262 deletions(-) delete mode 100644 host/lib/usrp/usrp2/clock_control.cpp delete mode 100644 host/lib/usrp/usrp2/clock_control.hpp create mode 100644 host/lib/usrp/usrp2/clock_ctrl.cpp create mode 100644 host/lib/usrp/usrp2/clock_ctrl.hpp create mode 100644 host/lib/usrp/usrp2/codec_ctrl.cpp create mode 100644 host/lib/usrp/usrp2/codec_ctrl.hpp (limited to 'host/lib') diff --git a/host/lib/usrp/usrp2/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt index f9907e21e..6c7881861 100644 --- a/host/lib/usrp/usrp2/CMakeLists.txt +++ b/host/lib/usrp/usrp2/CMakeLists.txt @@ -18,7 +18,8 @@ #This file will be included by cmake, use absolute paths! LIBUHD_APPEND_SOURCES( - ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/clock_control.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/clock_ctrl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_ctrl.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dboard_impl.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dboard_iface.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dsp_impl.cpp diff --git a/host/lib/usrp/usrp2/clock_control.cpp b/host/lib/usrp/usrp2/clock_control.cpp deleted file mode 100644 index 72f1f1c7a..000000000 --- a/host/lib/usrp/usrp2/clock_control.cpp +++ /dev/null @@ -1,157 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -#include "usrp2_impl.hpp" -#include "clock_control.hpp" -#include "ad9510_regs.hpp" -#include "usrp2_regs.hpp" //spi slave constants -#include - -using namespace uhd; -using namespace uhd::usrp; - -/*! - * A usrp2 clock control specific to the ad9510 ic. - */ -class clock_control_ad9510 : public clock_control{ -public: - clock_control_ad9510(usrp2_iface::sptr iface){ - _iface = iface; - - _ad9510_regs.cp_current_setting = ad9510_regs_t::CP_CURRENT_SETTING_3_0MA; - this->write_reg(0x09); - - // Setup the clock registers to 100MHz: - // This was already done by the firmware (or the host couldnt communicate). - // We could remove this part, and just leave it to the firmware. - // But why not leave it in for those who want to mess with clock settings? - // 100mhz = 10mhz/R * (P*B + A) - - _ad9510_regs.pll_power_down = ad9510_regs_t::PLL_POWER_DOWN_NORMAL; - _ad9510_regs.prescaler_value = ad9510_regs_t::PRESCALER_VALUE_DIV2; - this->write_reg(0x0A); - - _ad9510_regs.acounter = 0; - this->write_reg(0x04); - - _ad9510_regs.bcounter_msb = 0; - _ad9510_regs.bcounter_lsb = 5; - this->write_reg(0x05); - this->write_reg(0x06); - - _ad9510_regs.ref_counter_msb = 0; - _ad9510_regs.ref_counter_lsb = 1; // r divider = 1 - this->write_reg(0x0B); - this->write_reg(0x0C); - - /* regs will be updated in commands below */ - - this->enable_external_ref(false); - this->enable_rx_dboard_clock(false); - this->enable_tx_dboard_clock(false); - - /* private clock enables, must be set here */ - this->enable_dac_clock(true); - this->enable_adc_clock(true); - - } - - ~clock_control_ad9510(void){ - /* private clock enables, must be set here */ - this->enable_dac_clock(false); - this->enable_adc_clock(false); - } - - //uses output clock 7 (cmos) - void enable_rx_dboard_clock(bool enb){ - _ad9510_regs.power_down_lvds_cmos_out7 = enb? 0 : 1; - _ad9510_regs.lvds_cmos_select_out7 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT7_CMOS; - _ad9510_regs.output_level_lvds_out7 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT7_1_75MA; - this->write_reg(0x43); - this->update_regs(); - } - - //uses output clock 6 (cmos) - void enable_tx_dboard_clock(bool enb){ - _ad9510_regs.power_down_lvds_cmos_out6 = enb? 0 : 1; - _ad9510_regs.lvds_cmos_select_out6 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT6_CMOS; - _ad9510_regs.output_level_lvds_out6 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT6_1_75MA; - this->write_reg(0x42); - this->update_regs(); - } - - /*! - * If we are to use an external reference, enable the charge pump. - * \param enb true to enable the CP - */ - void enable_external_ref(bool enb){ - _ad9510_regs.charge_pump_mode = (enb)? - ad9510_regs_t::CHARGE_PUMP_MODE_NORMAL : - ad9510_regs_t::CHARGE_PUMP_MODE_3STATE ; - _ad9510_regs.pll_mux_control = ad9510_regs_t::PLL_MUX_CONTROL_DLD_HIGH; - _ad9510_regs.pfd_polarity = ad9510_regs_t::PFD_POLARITY_POS; - this->write_reg(0x08); - this->update_regs(); - } - -private: - /*! - * Write a single register to the spi regs. - * \param addr the address to write - */ - void write_reg(boost::uint8_t addr){ - boost::uint32_t data = _ad9510_regs.get_write_reg(addr); - _iface->transact_spi(SPI_SS_AD9510, spi_config_t::EDGE_RISE, data, 24, false /*no rb*/); - } - - /*! - * Tells the ad9510 to latch the settings into the operational registers. - */ - void update_regs(void){ - _ad9510_regs.update_registers = 1; - this->write_reg(0x5a); - } - - //uses output clock 3 (pecl) - void enable_dac_clock(bool enb){ - _ad9510_regs.power_down_lvpecl_out3 = (enb)? - ad9510_regs_t::POWER_DOWN_LVPECL_OUT3_NORMAL : - ad9510_regs_t::POWER_DOWN_LVPECL_OUT3_SAFE_PD; - _ad9510_regs.output_level_lvpecl_out3 = ad9510_regs_t::OUTPUT_LEVEL_LVPECL_OUT3_810MV; - this->write_reg(0x3F); - this->update_regs(); - } - - //uses output clock 4 (lvds) - void enable_adc_clock(bool enb){ - _ad9510_regs.power_down_lvds_cmos_out4 = enb? 0 : 1; - _ad9510_regs.lvds_cmos_select_out4 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT4_LVDS; - _ad9510_regs.output_level_lvds_out4 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT4_1_75MA; - this->write_reg(0x40); - this->update_regs(); - } - - usrp2_iface::sptr _iface; - ad9510_regs_t _ad9510_regs; -}; - -/*********************************************************************** - * Public make function for the ad9510 clock control - **********************************************************************/ -clock_control::sptr clock_control::make_ad9510(usrp2_iface::sptr iface){ - return clock_control::sptr(new clock_control_ad9510(iface)); -} diff --git a/host/lib/usrp/usrp2/clock_control.hpp b/host/lib/usrp/usrp2/clock_control.hpp deleted file mode 100644 index b64a53196..000000000 --- a/host/lib/usrp/usrp2/clock_control.hpp +++ /dev/null @@ -1,60 +0,0 @@ -// -// Copyright 2010 Ettus Research LLC -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -#ifndef INCLUDED_CLOCK_CONTROL_HPP -#define INCLUDED_CLOCK_CONTROL_HPP - -#include "usrp2_iface.hpp" -#include -#include - -class clock_control : boost::noncopyable{ -public: - typedef boost::shared_ptr sptr; - - /*! - * Make a clock config for the ad9510 ic. - * \param _iface a pointer to the usrp2 interface object - * \return a new clock control object - */ - static sptr make_ad9510(usrp2_iface::sptr iface); - - /*! - * Enable/disable the rx dboard clock. - * \param enb true to enable - */ - virtual void enable_rx_dboard_clock(bool enb) = 0; - - /*! - * Enable/disable the tx dboard clock. - * \param enb true to enable - */ - virtual void enable_tx_dboard_clock(bool enb) = 0; - - /*! - * Enable/disable external reference. - * \param enb true to enable - */ - virtual void enable_external_ref(bool enb) = 0; - - /*! - * TODO other clock control api here.... - */ - -}; - -#endif /* INCLUDED_CLOCK_CONTROL_HPP */ diff --git a/host/lib/usrp/usrp2/clock_ctrl.cpp b/host/lib/usrp/usrp2/clock_ctrl.cpp new file mode 100644 index 000000000..db8d8a886 --- /dev/null +++ b/host/lib/usrp/usrp2/clock_ctrl.cpp @@ -0,0 +1,155 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include "clock_ctrl.hpp" +#include "ad9510_regs.hpp" +#include "usrp2_regs.hpp" //spi slave constants +#include + +using namespace uhd; + +/*! + * A usrp2 clock control specific to the ad9510 ic. + */ +class clock_ctrl_impl : public clock_ctrl{ +public: + clock_ctrl_impl(usrp2_iface::sptr iface){ + _iface = iface; + + _ad9510_regs.cp_current_setting = ad9510_regs_t::CP_CURRENT_SETTING_3_0MA; + this->write_reg(0x09); + + // Setup the clock registers to 100MHz: + // This was already done by the firmware (or the host couldnt communicate). + // We could remove this part, and just leave it to the firmware. + // But why not leave it in for those who want to mess with clock settings? + // 100mhz = 10mhz/R * (P*B + A) + + _ad9510_regs.pll_power_down = ad9510_regs_t::PLL_POWER_DOWN_NORMAL; + _ad9510_regs.prescaler_value = ad9510_regs_t::PRESCALER_VALUE_DIV2; + this->write_reg(0x0A); + + _ad9510_regs.acounter = 0; + this->write_reg(0x04); + + _ad9510_regs.bcounter_msb = 0; + _ad9510_regs.bcounter_lsb = 5; + this->write_reg(0x05); + this->write_reg(0x06); + + _ad9510_regs.ref_counter_msb = 0; + _ad9510_regs.ref_counter_lsb = 1; // r divider = 1 + this->write_reg(0x0B); + this->write_reg(0x0C); + + /* regs will be updated in commands below */ + + this->enable_external_ref(false); + this->enable_rx_dboard_clock(false); + this->enable_tx_dboard_clock(false); + + /* private clock enables, must be set here */ + this->enable_dac_clock(true); + this->enable_adc_clock(true); + + } + + ~clock_ctrl_impl(void){ + /* private clock enables, must be set here */ + this->enable_dac_clock(false); + this->enable_adc_clock(false); + } + + //uses output clock 7 (cmos) + void enable_rx_dboard_clock(bool enb){ + _ad9510_regs.power_down_lvds_cmos_out7 = enb? 0 : 1; + _ad9510_regs.lvds_cmos_select_out7 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT7_CMOS; + _ad9510_regs.output_level_lvds_out7 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT7_1_75MA; + this->write_reg(0x43); + this->update_regs(); + } + + //uses output clock 6 (cmos) + void enable_tx_dboard_clock(bool enb){ + _ad9510_regs.power_down_lvds_cmos_out6 = enb? 0 : 1; + _ad9510_regs.lvds_cmos_select_out6 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT6_CMOS; + _ad9510_regs.output_level_lvds_out6 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT6_1_75MA; + this->write_reg(0x42); + this->update_regs(); + } + + /*! + * If we are to use an external reference, enable the charge pump. + * \param enb true to enable the CP + */ + void enable_external_ref(bool enb){ + _ad9510_regs.charge_pump_mode = (enb)? + ad9510_regs_t::CHARGE_PUMP_MODE_NORMAL : + ad9510_regs_t::CHARGE_PUMP_MODE_3STATE ; + _ad9510_regs.pll_mux_control = ad9510_regs_t::PLL_MUX_CONTROL_DLD_HIGH; + _ad9510_regs.pfd_polarity = ad9510_regs_t::PFD_POLARITY_POS; + this->write_reg(0x08); + this->update_regs(); + } + +private: + /*! + * Write a single register to the spi regs. + * \param addr the address to write + */ + void write_reg(boost::uint8_t addr){ + boost::uint32_t data = _ad9510_regs.get_write_reg(addr); + _iface->transact_spi(SPI_SS_AD9510, spi_config_t::EDGE_RISE, data, 24, false /*no rb*/); + } + + /*! + * Tells the ad9510 to latch the settings into the operational registers. + */ + void update_regs(void){ + _ad9510_regs.update_registers = 1; + this->write_reg(0x5a); + } + + //uses output clock 3 (pecl) + void enable_dac_clock(bool enb){ + _ad9510_regs.power_down_lvpecl_out3 = (enb)? + ad9510_regs_t::POWER_DOWN_LVPECL_OUT3_NORMAL : + ad9510_regs_t::POWER_DOWN_LVPECL_OUT3_SAFE_PD; + _ad9510_regs.output_level_lvpecl_out3 = ad9510_regs_t::OUTPUT_LEVEL_LVPECL_OUT3_810MV; + this->write_reg(0x3F); + this->update_regs(); + } + + //uses output clock 4 (lvds) + void enable_adc_clock(bool enb){ + _ad9510_regs.power_down_lvds_cmos_out4 = enb? 0 : 1; + _ad9510_regs.lvds_cmos_select_out4 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT4_LVDS; + _ad9510_regs.output_level_lvds_out4 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT4_1_75MA; + this->write_reg(0x40); + this->update_regs(); + } + + usrp2_iface::sptr _iface; + ad9510_regs_t _ad9510_regs; +}; + +/*********************************************************************** + * Public make function for the ad9510 clock control + **********************************************************************/ +clock_ctrl::sptr clock_ctrl::make(usrp2_iface::sptr iface){ + return sptr(new clock_ctrl_impl(iface)); +} diff --git a/host/lib/usrp/usrp2/clock_ctrl.hpp b/host/lib/usrp/usrp2/clock_ctrl.hpp new file mode 100644 index 000000000..3208008a9 --- /dev/null +++ b/host/lib/usrp/usrp2/clock_ctrl.hpp @@ -0,0 +1,60 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#ifndef INCLUDED_CLOCK_CONTROL_HPP +#define INCLUDED_CLOCK_CONTROL_HPP + +#include "usrp2_iface.hpp" +#include +#include + +class clock_ctrl : boost::noncopyable{ +public: + typedef boost::shared_ptr sptr; + + /*! + * Make a clock config for the ad9510 ic. + * \param _iface a pointer to the usrp2 interface object + * \return a new clock control object + */ + static sptr make(usrp2_iface::sptr iface); + + /*! + * Enable/disable the rx dboard clock. + * \param enb true to enable + */ + virtual void enable_rx_dboard_clock(bool enb) = 0; + + /*! + * Enable/disable the tx dboard clock. + * \param enb true to enable + */ + virtual void enable_tx_dboard_clock(bool enb) = 0; + + /*! + * Enable/disable external reference. + * \param enb true to enable + */ + virtual void enable_external_ref(bool enb) = 0; + + /*! + * TODO other clock control api here.... + */ + +}; + +#endif /* INCLUDED_CLOCK_CONTROL_HPP */ diff --git a/host/lib/usrp/usrp2/codec_ctrl.cpp b/host/lib/usrp/usrp2/codec_ctrl.cpp new file mode 100644 index 000000000..452aa39b1 --- /dev/null +++ b/host/lib/usrp/usrp2/codec_ctrl.cpp @@ -0,0 +1,91 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include "codec_ctrl.hpp" +#include "ad9777_regs.hpp" +#include "usrp2_regs.hpp" +#include +#include +#include + +static const bool codec_ctrl_debug = false; + +using namespace uhd; + +/*! + * A usrp2 codec control specific to the ad9777 ic. + */ +class codec_ctrl_impl : public codec_ctrl{ +public: + codec_ctrl_impl(usrp2_iface::sptr iface){ + _iface = iface; + + //setup the ad9777 dac + _ad9777_regs.x_1r_2r_mode = ad9777_regs_t::X_1R_2R_MODE_1R; + _ad9777_regs.filter_interp_rate = ad9777_regs_t::FILTER_INTERP_RATE_4X; + _ad9777_regs.mix_mode = ad9777_regs_t::MIX_MODE_REAL; + _ad9777_regs.pll_divide_ratio = ad9777_regs_t::PLL_DIVIDE_RATIO_DIV1; + _ad9777_regs.pll_state = ad9777_regs_t::PLL_STATE_OFF; + _ad9777_regs.auto_cp_control = ad9777_regs_t::AUTO_CP_CONTROL_ENB; + //I dac values + _ad9777_regs.idac_fine_gain_adjust = 0; + _ad9777_regs.idac_coarse_gain_adjust = 0xf; + _ad9777_regs.idac_offset_adjust_lsb = 0; + _ad9777_regs.idac_offset_adjust_msb = 0; + //Q dac values + _ad9777_regs.qdac_fine_gain_adjust = 0; + _ad9777_regs.qdac_coarse_gain_adjust = 0xf; + _ad9777_regs.qdac_offset_adjust_lsb = 0; + _ad9777_regs.qdac_offset_adjust_msb = 0; + //write all regs + for(boost::uint8_t addr = 0; addr <= 0xC; addr++){ + send_ad9777_reg(addr); + } + + //power-up adc + _iface->poke32(FR_MISC_CTRL_ADC, FRF_MISC_CTRL_ADC_ON); + } + + ~codec_ctrl_impl(void){ + //power-down dac + _ad9777_regs.power_down_mode = 1; + send_ad9777_reg(0); + + //power-down adc + _iface->poke32(FR_MISC_CTRL_ADC, FRF_MISC_CTRL_ADC_OFF); + } + +private: + ad9777_regs_t _ad9777_regs; + usrp2_iface::sptr _iface; + + void send_ad9777_reg(boost::uint8_t addr){ + boost::uint16_t reg = _ad9777_regs.get_write_reg(addr); + if (codec_ctrl_debug) std::cout << "send_ad9777_reg: " << std::hex << reg << std::endl; + _iface->transact_spi( + SPI_SS_AD9777, spi_config_t::EDGE_RISE, + reg, 6, false /*no rb*/ + ); + } +}; + +/*********************************************************************** + * Public make function for the usrp2 codec control + **********************************************************************/ +codec_ctrl::sptr codec_ctrl::make(usrp2_iface::sptr iface){ + return sptr(new codec_ctrl_impl(iface)); +} diff --git a/host/lib/usrp/usrp2/codec_ctrl.hpp b/host/lib/usrp/usrp2/codec_ctrl.hpp new file mode 100644 index 000000000..c34fb8159 --- /dev/null +++ b/host/lib/usrp/usrp2/codec_ctrl.hpp @@ -0,0 +1,38 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#ifndef INCLUDED_CODEC_CONTROL_HPP +#define INCLUDED_CODEC_CONTROL_HPP + +#include "usrp2_iface.hpp" +#include +#include + +class codec_ctrl : boost::noncopyable{ +public: + typedef boost::shared_ptr sptr; + + /*! + * Make a codec control for the DAC and ADC. + * \param _iface a pointer to the usrp2 interface object + * \return a new codec control object + */ + static sptr make(usrp2_iface::sptr iface); + +}; + +#endif /* INCLUDED_CODEC_CONTROL_HPP */ diff --git a/host/lib/usrp/usrp2/dboard_iface.cpp b/host/lib/usrp/usrp2/dboard_iface.cpp index 372a5af07..d33a11fd6 100644 --- a/host/lib/usrp/usrp2/dboard_iface.cpp +++ b/host/lib/usrp/usrp2/dboard_iface.cpp @@ -16,7 +16,7 @@ // #include "usrp2_iface.hpp" -#include "clock_control.hpp" +#include "clock_ctrl.hpp" #include "usrp2_regs.hpp" //wishbone address constants #include #include @@ -33,7 +33,7 @@ using namespace boost::assign; class usrp2_dboard_iface : public dboard_iface{ public: - usrp2_dboard_iface(usrp2_iface::sptr iface, clock_control::sptr clk_ctrl); + usrp2_dboard_iface(usrp2_iface::sptr iface, clock_ctrl::sptr clock_ctrl); ~usrp2_dboard_iface(void); void write_aux_dac(unit_t, int, float); @@ -66,7 +66,7 @@ public: private: usrp2_iface::sptr _iface; - clock_control::sptr _clk_ctrl; + clock_ctrl::sptr _clock_ctrl; boost::uint32_t _ddr_shadow; uhd::dict _dac_regs; @@ -78,17 +78,17 @@ private: **********************************************************************/ dboard_iface::sptr make_usrp2_dboard_iface( usrp2_iface::sptr iface, - clock_control::sptr clk_ctrl + clock_ctrl::sptr clock_ctrl ){ - return dboard_iface::sptr(new usrp2_dboard_iface(iface, clk_ctrl)); + return dboard_iface::sptr(new usrp2_dboard_iface(iface, clock_ctrl)); } /*********************************************************************** * Structors **********************************************************************/ -usrp2_dboard_iface::usrp2_dboard_iface(usrp2_iface::sptr iface, clock_control::sptr clk_ctrl){ +usrp2_dboard_iface::usrp2_dboard_iface(usrp2_iface::sptr iface, clock_ctrl::sptr clock_ctrl){ _iface = iface; - _clk_ctrl = clk_ctrl; + _clock_ctrl = clock_ctrl; _ddr_shadow = 0; //set the selection mux to use atr @@ -123,8 +123,8 @@ double usrp2_dboard_iface::get_clock_rate(unit_t){ void usrp2_dboard_iface::set_clock_enabled(unit_t unit, bool enb){ switch(unit){ - case UNIT_RX: _clk_ctrl->enable_rx_dboard_clock(enb); return; - case UNIT_TX: _clk_ctrl->enable_tx_dboard_clock(enb); return; + case UNIT_RX: _clock_ctrl->enable_rx_dboard_clock(enb); return; + case UNIT_TX: _clock_ctrl->enable_tx_dboard_clock(enb); return; } } diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp index 403faf5cf..0f8a739f2 100644 --- a/host/lib/usrp/usrp2/dboard_impl.cpp +++ b/host/lib/usrp/usrp2/dboard_impl.cpp @@ -39,7 +39,7 @@ void usrp2_impl::dboard_init(void){ //create a new dboard interface and manager dboard_iface::sptr _dboard_iface( - make_usrp2_dboard_iface(_iface, _clk_ctrl) + make_usrp2_dboard_iface(_iface, _clock_ctrl) ); _dboard_manager = dboard_manager::make( _rx_db_eeprom.id, _tx_db_eeprom.id, _dboard_iface diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 2c8fd2df4..892e45f49 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -17,7 +17,6 @@ #include "usrp2_impl.hpp" #include "usrp2_regs.hpp" -#include "ad9777_regs.hpp" #include #include #include @@ -38,35 +37,6 @@ void usrp2_impl::mboard_init(void){ boost::bind(&usrp2_impl::mboard_set, this, _1, _2) ); - _clk_ctrl = clock_control::make_ad9510(_iface); - - //setup the ad9777 dac - ad9777_regs_t ad9777_regs; - ad9777_regs.x_1r_2r_mode = ad9777_regs_t::X_1R_2R_MODE_1R; - ad9777_regs.filter_interp_rate = ad9777_regs_t::FILTER_INTERP_RATE_4X; - ad9777_regs.mix_mode = ad9777_regs_t::MIX_MODE_REAL; - ad9777_regs.pll_divide_ratio = ad9777_regs_t::PLL_DIVIDE_RATIO_DIV1; - ad9777_regs.pll_state = ad9777_regs_t::PLL_STATE_OFF; - ad9777_regs.auto_cp_control = ad9777_regs_t::AUTO_CP_CONTROL_ENB; - //I dac values - ad9777_regs.idac_fine_gain_adjust = 0; - ad9777_regs.idac_coarse_gain_adjust = 0xf; - ad9777_regs.idac_offset_adjust_lsb = 0; - ad9777_regs.idac_offset_adjust_msb = 0; - //Q dac values - ad9777_regs.qdac_fine_gain_adjust = 0; - ad9777_regs.qdac_coarse_gain_adjust = 0xf; - ad9777_regs.qdac_offset_adjust_lsb = 0; - ad9777_regs.qdac_offset_adjust_msb = 0; - //write all regs - for(boost::uint8_t addr = 0; addr <= 0xC; addr++){ - boost::uint16_t data = ad9777_regs.get_write_reg(addr); - _iface->transact_spi(SPI_SS_AD9777, spi_config_t::EDGE_RISE, data, 16, false /*no rb*/); - } - - //enable ADCs - _iface->poke32(FR_MISC_CTRL_ADC, FRF_MISC_CTRL_ADC_ON); - //set up serdes _iface->poke32(FR_MISC_CTRL_SERDES, FRF_MISC_CTRL_SERDES_ENABLE | FRF_MISC_CTRL_SERDES_RXEN); @@ -112,7 +82,7 @@ void usrp2_impl::update_clock_config(void){ //clock source ref 10mhz bool use_external = _clock_config.ref_source != clock_config_t::REF_INT; - _clk_ctrl->enable_external_ref(use_external); + _clock_ctrl->enable_external_ref(use_external); } void usrp2_impl::set_time_spec(const time_spec_t &time_spec, bool now){ diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 1dde8c054..ef7754c33 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -147,6 +147,8 @@ usrp2_impl::usrp2_impl( //make a new interface for usrp2 stuff _iface = usrp2_iface::make(ctrl_transport); + _clock_ctrl = clock_ctrl::make(_iface); + _codec_ctrl = codec_ctrl::make(_iface); //load the allowed decim/interp rates //_USRP2_RATES = range(4, 128+1, 1) + range(130, 256+1, 2) + range(260, 512+1, 4) diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 1c9387744..871050356 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -19,7 +19,8 @@ #define INCLUDED_USRP2_IMPL_HPP #include "usrp2_iface.hpp" -#include "clock_control.hpp" +#include "clock_ctrl.hpp" +#include "codec_ctrl.hpp" #include #include #include @@ -40,7 +41,7 @@ */ uhd::usrp::dboard_iface::sptr make_usrp2_dboard_iface( usrp2_iface::sptr iface, - clock_control::sptr clk_ctrl + clock_ctrl::sptr clk_ctrl ); /*! @@ -114,7 +115,8 @@ private: void set(const wax::obj &, const wax::obj &); //interfaces - clock_control::sptr _clk_ctrl; + clock_ctrl::sptr _clock_ctrl; + codec_ctrl::sptr _codec_ctrl; usrp2_iface::sptr _iface; //the raw io interface (samples are in the usrp2 native format) -- cgit v1.2.3 From 7c7b0d0a0dc8dd0cb4f0229fbc55978d6f2e253c Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 10 May 2010 16:37:12 -0700 Subject: Added a place for serdes control on the host. Fix bug in codec control. Comment out some clock control in fw code. --- firmware/microblaze/lib/clocks.c | 30 ++++++++++++------------ firmware/microblaze/lib/clocks.h | 10 ++++---- host/lib/usrp/usrp2/CMakeLists.txt | 1 + host/lib/usrp/usrp2/clock_ctrl.hpp | 6 ++--- host/lib/usrp/usrp2/codec_ctrl.cpp | 6 ++--- host/lib/usrp/usrp2/codec_ctrl.hpp | 6 ++--- host/lib/usrp/usrp2/mboard_impl.cpp | 4 ---- host/lib/usrp/usrp2/serdes_ctrl.cpp | 46 +++++++++++++++++++++++++++++++++++++ host/lib/usrp/usrp2/serdes_ctrl.hpp | 40 ++++++++++++++++++++++++++++++++ host/lib/usrp/usrp2/usrp2_impl.cpp | 1 + host/lib/usrp/usrp2/usrp2_impl.hpp | 4 +++- 11 files changed, 120 insertions(+), 34 deletions(-) create mode 100644 host/lib/usrp/usrp2/serdes_ctrl.cpp create mode 100644 host/lib/usrp/usrp2/serdes_ctrl.hpp (limited to 'host/lib') diff --git a/firmware/microblaze/lib/clocks.c b/firmware/microblaze/lib/clocks.c index d9d4fcd3c..ccc4a7cc7 100644 --- a/firmware/microblaze/lib/clocks.c +++ b/firmware/microblaze/lib/clocks.c @@ -48,14 +48,14 @@ clocks_init(void) clocks_mimo_config(MC_WE_DONT_LOCK); // Set up other clocks - clocks_enable_test_clk(false, 0); - clocks_enable_tx_dboard(false, 0); - clocks_enable_rx_dboard(false, 0); + //clocks_enable_test_clk(false, 0); + //clocks_enable_tx_dboard(false, 0); + //clocks_enable_rx_dboard(false, 0); clocks_enable_eth_phyclk(false, 0); // Enable clock to ADCs and DACs - clocks_enable_dac_clk(true, 1); - clocks_enable_adc_clk(true, 1); + //clocks_enable_dac_clk(true, 1); + //clocks_enable_adc_clk(true, 1); } @@ -168,11 +168,11 @@ clocks_enable_XXX_clk(bool enable, int divisor, int reg_en, int reg_div, int mod } // Clock 0 -void +/*void clocks_enable_test_clk(bool enable, int divisor) { clocks_enable_XXX_clk(enable,divisor,0x3C,0x48,CLOCK_MODE_PECL); -} +}*/ // Clock 1 void @@ -211,29 +211,29 @@ clocks_enable_eth_phyclk(bool enable, int divisor) } // Clock 3 -void +/*void clocks_enable_dac_clk(bool enable, int divisor) { clocks_enable_XXX_clk(enable,divisor,0x3F,0x4E,CLOCK_MODE_PECL); -} +}*/ // Clock 4 -void +/*void clocks_enable_adc_clk(bool enable, int divisor) { clocks_enable_XXX_clk(enable,divisor,0x40,0x50,CLOCK_MODE_LVDS); -} +}*/ // Clock 6 -void +/*void clocks_enable_tx_dboard(bool enable, int divisor) { clocks_enable_XXX_clk(enable,divisor,0x42,0x54,CLOCK_MODE_CMOS); -} +}*/ // Clock 7 -void +/*void clocks_enable_rx_dboard(bool enable, int divisor) { clocks_enable_XXX_clk(enable,divisor,0x43,0x56,CLOCK_MODE_CMOS); -} +}*/ diff --git a/firmware/microblaze/lib/clocks.h b/firmware/microblaze/lib/clocks.h index 141fc61e0..43d5a05c2 100644 --- a/firmware/microblaze/lib/clocks.h +++ b/firmware/microblaze/lib/clocks.h @@ -53,7 +53,7 @@ bool clocks_lock_detect(); /*! * \brief Enable or disable test clock (extra clock signal) */ -void clocks_enable_test_clk(bool enable, int divisor); +//void clocks_enable_test_clk(bool enable, int divisor); /*! * \brief Enable or disable fpga clock. Disabling would wedge and require a power cycle. @@ -73,23 +73,23 @@ void clocks_enable_eth_phyclk(bool enable, int divisor); /*! * \brief Enable or disable clock to DAC */ -void clocks_enable_dac_clk(bool enable, int divisor); +//void clocks_enable_dac_clk(bool enable, int divisor); /*! * \brief Enable or disable clock to ADC */ -void clocks_enable_adc_clk(bool enable, int divisor); +//void clocks_enable_adc_clk(bool enable, int divisor); /*! * \brief Enable or disable clock to Rx daughterboard */ -void clocks_enable_rx_dboard(bool enable, int divisor); +//void clocks_enable_rx_dboard(bool enable, int divisor); /*! * \brief Enable or disable clock to Tx daughterboard */ -void clocks_enable_tx_dboard(bool enable, int divisor); +//void clocks_enable_tx_dboard(bool enable, int divisor); #endif /* INCLUDED_CLOCKS_H */ diff --git a/host/lib/usrp/usrp2/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt index 6c7881861..fee67dff9 100644 --- a/host/lib/usrp/usrp2/CMakeLists.txt +++ b/host/lib/usrp/usrp2/CMakeLists.txt @@ -25,6 +25,7 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dsp_impl.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/io_impl.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/mboard_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/serdes_ctrl.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_iface.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_impl.cpp ) diff --git a/host/lib/usrp/usrp2/clock_ctrl.hpp b/host/lib/usrp/usrp2/clock_ctrl.hpp index 3208008a9..706bf4246 100644 --- a/host/lib/usrp/usrp2/clock_ctrl.hpp +++ b/host/lib/usrp/usrp2/clock_ctrl.hpp @@ -15,8 +15,8 @@ // along with this program. If not, see . // -#ifndef INCLUDED_CLOCK_CONTROL_HPP -#define INCLUDED_CLOCK_CONTROL_HPP +#ifndef INCLUDED_CLOCK_CTRL_HPP +#define INCLUDED_CLOCK_CTRL_HPP #include "usrp2_iface.hpp" #include @@ -57,4 +57,4 @@ public: }; -#endif /* INCLUDED_CLOCK_CONTROL_HPP */ +#endif /* INCLUDED_CLOCK_CTRL_HPP */ diff --git a/host/lib/usrp/usrp2/codec_ctrl.cpp b/host/lib/usrp/usrp2/codec_ctrl.cpp index 452aa39b1..d1e16881b 100644 --- a/host/lib/usrp/usrp2/codec_ctrl.cpp +++ b/host/lib/usrp/usrp2/codec_ctrl.cpp @@ -53,7 +53,7 @@ public: _ad9777_regs.qdac_offset_adjust_msb = 0; //write all regs for(boost::uint8_t addr = 0; addr <= 0xC; addr++){ - send_ad9777_reg(addr); + this->send_ad9777_reg(addr); } //power-up adc @@ -63,7 +63,7 @@ public: ~codec_ctrl_impl(void){ //power-down dac _ad9777_regs.power_down_mode = 1; - send_ad9777_reg(0); + this->send_ad9777_reg(0); //power-down adc _iface->poke32(FR_MISC_CTRL_ADC, FRF_MISC_CTRL_ADC_OFF); @@ -78,7 +78,7 @@ private: if (codec_ctrl_debug) std::cout << "send_ad9777_reg: " << std::hex << reg << std::endl; _iface->transact_spi( SPI_SS_AD9777, spi_config_t::EDGE_RISE, - reg, 6, false /*no rb*/ + reg, 16, false /*no rb*/ ); } }; diff --git a/host/lib/usrp/usrp2/codec_ctrl.hpp b/host/lib/usrp/usrp2/codec_ctrl.hpp index c34fb8159..0ee52f476 100644 --- a/host/lib/usrp/usrp2/codec_ctrl.hpp +++ b/host/lib/usrp/usrp2/codec_ctrl.hpp @@ -15,8 +15,8 @@ // along with this program. If not, see . // -#ifndef INCLUDED_CODEC_CONTROL_HPP -#define INCLUDED_CODEC_CONTROL_HPP +#ifndef INCLUDED_CODEC_CTRL_HPP +#define INCLUDED_CODEC_CTRL_HPP #include "usrp2_iface.hpp" #include @@ -35,4 +35,4 @@ public: }; -#endif /* INCLUDED_CODEC_CONTROL_HPP */ +#endif /* INCLUDED_CODEC_CTRL_HPP */ diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 892e45f49..7e62bedf0 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -36,10 +36,6 @@ void usrp2_impl::mboard_init(void){ boost::bind(&usrp2_impl::mboard_get, this, _1, _2), boost::bind(&usrp2_impl::mboard_set, this, _1, _2) ); - - //set up serdes - _iface->poke32(FR_MISC_CTRL_SERDES, FRF_MISC_CTRL_SERDES_ENABLE | FRF_MISC_CTRL_SERDES_RXEN); - } void usrp2_impl::init_clock_config(void){ diff --git a/host/lib/usrp/usrp2/serdes_ctrl.cpp b/host/lib/usrp/usrp2/serdes_ctrl.cpp new file mode 100644 index 000000000..dde22b499 --- /dev/null +++ b/host/lib/usrp/usrp2/serdes_ctrl.cpp @@ -0,0 +1,46 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include "serdes_ctrl.hpp" +#include "usrp2_regs.hpp" + +using namespace uhd; + +/*! + * A usrp2 serdes control implementation + */ +class serdes_ctrl_impl : public serdes_ctrl{ +public: + serdes_ctrl_impl(usrp2_iface::sptr iface){ + _iface = iface; + _iface->poke32(FR_MISC_CTRL_SERDES, FRF_MISC_CTRL_SERDES_ENABLE | FRF_MISC_CTRL_SERDES_RXEN); + } + + ~serdes_ctrl_impl(void){ + _iface->poke32(FR_MISC_CTRL_SERDES, 0); //power-down + } + +private: + usrp2_iface::sptr _iface; +}; + +/*********************************************************************** + * Public make function for the usrp2 serdes control + **********************************************************************/ +serdes_ctrl::sptr serdes_ctrl::make(usrp2_iface::sptr iface){ + return sptr(new serdes_ctrl_impl(iface)); +} diff --git a/host/lib/usrp/usrp2/serdes_ctrl.hpp b/host/lib/usrp/usrp2/serdes_ctrl.hpp new file mode 100644 index 000000000..586238739 --- /dev/null +++ b/host/lib/usrp/usrp2/serdes_ctrl.hpp @@ -0,0 +1,40 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#ifndef INCLUDED_SERDES_CTRL_HPP +#define INCLUDED_SERDES_CTRL_HPP + +#include "usrp2_iface.hpp" +#include +#include + +class serdes_ctrl : boost::noncopyable{ +public: + typedef boost::shared_ptr sptr; + + /*! + * Make a serdes control object for the usrp2 serdes port. + * \param _iface a pointer to the usrp2 interface object + * \return a new serdes control object + */ + static sptr make(usrp2_iface::sptr iface); + + //TODO fill me in with virtual methods + +}; + +#endif /* INCLUDED_SERDES_CTRL_HPP */ diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index ef7754c33..5c1d7f9e3 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -149,6 +149,7 @@ usrp2_impl::usrp2_impl( _iface = usrp2_iface::make(ctrl_transport); _clock_ctrl = clock_ctrl::make(_iface); _codec_ctrl = codec_ctrl::make(_iface); + _serdes_ctrl = serdes_ctrl::make(_iface); //load the allowed decim/interp rates //_USRP2_RATES = range(4, 128+1, 1) + range(130, 256+1, 2) + range(260, 512+1, 4) diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 871050356..c5b6af810 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -21,6 +21,7 @@ #include "usrp2_iface.hpp" #include "clock_ctrl.hpp" #include "codec_ctrl.hpp" +#include "serdes_ctrl.hpp" #include #include #include @@ -115,9 +116,10 @@ private: void set(const wax::obj &, const wax::obj &); //interfaces + usrp2_iface::sptr _iface; clock_ctrl::sptr _clock_ctrl; codec_ctrl::sptr _codec_ctrl; - usrp2_iface::sptr _iface; + serdes_ctrl::sptr _serdes_ctrl; //the raw io interface (samples are in the usrp2 native format) void recv_raw(uhd::rx_metadata_t &); -- cgit v1.2.3 From 81f211c94f761c92baaf1a2997a7f9b9b7718182 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 11 May 2010 16:35:01 -0700 Subject: Moved usrp2 eeprom addr read/write to host control over i2c/eeprom interface calls. No longer part of the dude/bro protocol. Simplified the mac and ip addr read write code in mboard impl. Modified the mac addr type to take byte_vector_t from serial.hpp types. --- firmware/microblaze/apps/txrx_uhd.c | 23 +++-------------- host/include/uhd/types/mac_addr.hpp | 16 +++++------- host/include/uhd/utils/algorithm.hpp | 5 ++++ host/lib/types.cpp | 27 ++++++++++--------- host/lib/usrp/usrp2/fw_common.h | 10 ++------ host/lib/usrp/usrp2/mboard_impl.cpp | 50 +++++++++--------------------------- host/lib/usrp/usrp2/usrp2_iface.hpp | 7 +++++ host/lib/usrp/usrp2/usrp2_impl.cpp | 4 +-- 8 files changed, 53 insertions(+), 89 deletions(-) (limited to 'host/lib') diff --git a/firmware/microblaze/apps/txrx_uhd.c b/firmware/microblaze/apps/txrx_uhd.c index db830fa51..7ad4ab110 100644 --- a/firmware/microblaze/apps/txrx_uhd.c +++ b/firmware/microblaze/apps/txrx_uhd.c @@ -185,7 +185,7 @@ void handle_udp_ctrl_packet( printf("!Error in control packet handler: Expected protocol version %d, but got %d\n", USRP2_PROTO_VERSION, ctrl_data_in->proto_ver ); - ctrl_data_in_id = USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO; + ctrl_data_in_id = USRP2_CTRL_ID_WAZZUP_BRO; } //ensure that this is not a short packet @@ -209,28 +209,11 @@ void handle_udp_ctrl_packet( /******************************************************************* * Addressing ******************************************************************/ - case USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO: - ctrl_data_out.id = USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE; + case USRP2_CTRL_ID_WAZZUP_BRO: + ctrl_data_out.id = USRP2_CTRL_ID_WAZZUP_DUDE; memcpy(&ctrl_data_out.data.ip_addr, get_ip_addr(), sizeof(struct ip_addr)); break; - case USRP2_CTRL_ID_HERE_IS_A_NEW_IP_ADDR_BRO: - ctrl_data_out.id = USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE; - set_ip_addr((struct ip_addr *)&ctrl_data_in->data.ip_addr); - memcpy(&ctrl_data_out.data.ip_addr, get_ip_addr(), sizeof(struct ip_addr)); - break; - - case USRP2_CTRL_ID_GIVE_ME_YOUR_MAC_ADDR_BRO: - ctrl_data_out.id = USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE; - memcpy(&ctrl_data_out.data.mac_addr, ethernet_mac_addr(), sizeof(eth_mac_addr_t)); - break; - - case USRP2_CTRL_ID_HERE_IS_A_NEW_MAC_ADDR_BRO: - ctrl_data_out.id = USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE; - ethernet_set_mac_addr((eth_mac_addr_t *)&ctrl_data_in->data.mac_addr); - memcpy(&ctrl_data_out.data.mac_addr, ethernet_mac_addr(), sizeof(eth_mac_addr_t)); - break; - /******************************************************************* * SPI ******************************************************************/ diff --git a/host/include/uhd/types/mac_addr.hpp b/host/include/uhd/types/mac_addr.hpp index 3cd1fe86b..034b6a348 100644 --- a/host/include/uhd/types/mac_addr.hpp +++ b/host/include/uhd/types/mac_addr.hpp @@ -19,7 +19,7 @@ #define INCLUDED_UHD_TYPES_MAC_ADDR_HPP #include -#include +#include #include namespace uhd{ @@ -30,14 +30,12 @@ namespace uhd{ */ class UHD_API mac_addr_t{ public: - static const size_t hlen = 6; - /*! * Create a mac address a byte array. - * \param bytes a pointer for the byte array + * \param bytes a vector of bytes * \return a new mac address */ - static mac_addr_t from_bytes(const boost::uint8_t *bytes); + static mac_addr_t from_bytes(const byte_vector_t &bytes); /*! * Create a mac address from a string. @@ -48,9 +46,9 @@ namespace uhd{ /*! * Get the byte representation of the mac address. - * \return a pointer to the internal byte array + * \return a vector of bytes */ - const boost::uint8_t *to_bytes(void) const; + byte_vector_t to_bytes(void) const; /*! * Get the string representation of this mac address. @@ -59,8 +57,8 @@ namespace uhd{ std::string to_string(void) const; private: - mac_addr_t(const boost::uint8_t *bytes); //private constructor - boost::uint8_t _bytes[hlen]; //internal representation + mac_addr_t(const byte_vector_t &bytes); //private constructor + byte_vector_t _bytes; //internal representation }; } //namespace uhd diff --git a/host/include/uhd/utils/algorithm.hpp b/host/include/uhd/utils/algorithm.hpp index 72b655745..146b56c63 100644 --- a/host/include/uhd/utils/algorithm.hpp +++ b/host/include/uhd/utils/algorithm.hpp @@ -26,6 +26,11 @@ */ namespace std{ + template inline + void copy(const RangeSrc &src, RangeDst &dst){ + std::copy(boost::begin(src), boost::end(src), boost::begin(dst)); + } + template inline bool has(const Range &range, const T &value){ return boost::end(range) != std::find(boost::begin(range), boost::end(range), value); diff --git a/host/lib/types.cpp b/host/lib/types.cpp index ec9c8ac01..33eb550a1 100644 --- a/host/lib/types.cpp +++ b/host/lib/types.cpp @@ -15,6 +15,7 @@ // along with this program. If not, see . // +#include #include #include #include @@ -164,17 +165,19 @@ std::string device_addr_t::to_string(void) const{ /*********************************************************************** * mac addr **********************************************************************/ -mac_addr_t::mac_addr_t(const boost::uint8_t *bytes){ - std::copy(bytes, bytes+hlen, _bytes); +mac_addr_t::mac_addr_t(const byte_vector_t &bytes){ + UHD_ASSERT_THROW(bytes.size() == 6); + _bytes = bytes; } -mac_addr_t mac_addr_t::from_bytes(const boost::uint8_t *bytes){ +mac_addr_t mac_addr_t::from_bytes(const byte_vector_t &bytes){ return mac_addr_t(bytes); } mac_addr_t mac_addr_t::from_string(const std::string &mac_addr_str){ - boost::uint8_t p[hlen] = {0x00, 0x50, 0xC2, 0x85, 0x30, 0x00}; // Matt's IAB + byte_vector_t bytes = boost::assign::list_of + (0x00)(0x50)(0xC2)(0x85)(0x30)(0x00); // Matt's IAB try{ //only allow patterns of xx:xx or xx:xx:xx:xx:xx:xx @@ -189,7 +192,7 @@ mac_addr_t mac_addr_t::from_string(const std::string &mac_addr_str){ int hex_num; std::istringstream iss(hex_strs[i]); iss >> std::hex >> hex_num; - p[i] = boost::uint8_t(hex_num); + bytes[i] = boost::uint8_t(hex_num); } } @@ -199,19 +202,19 @@ mac_addr_t mac_addr_t::from_string(const std::string &mac_addr_str){ )); } - return from_bytes(p); + return mac_addr_t::from_bytes(bytes); } -const boost::uint8_t *mac_addr_t::to_bytes(void) const{ +byte_vector_t mac_addr_t::to_bytes(void) const{ return _bytes; } std::string mac_addr_t::to_string(void) const{ - return str( - boost::format("%02x:%02x:%02x:%02x:%02x:%02x") - % int(to_bytes()[0]) % int(to_bytes()[1]) % int(to_bytes()[2]) - % int(to_bytes()[3]) % int(to_bytes()[4]) % int(to_bytes()[5]) - ); + std::string addr = ""; + BOOST_FOREACH(boost::uint8_t byte, this->to_bytes()){ + addr += str(boost::format("%s%02x") % ((addr == "")?"":":") % int(byte)); + } + return addr; } /*********************************************************************** diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index f28013cf6..75f5b1779 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -53,13 +53,8 @@ typedef enum{ //USRP2_CTRL_ID_FOR_SURE, //TODO error condition enums //USRP2_CTRL_ID_SUX_MAN, - USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO = 'a', - USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE = 'A', - USRP2_CTRL_ID_HERE_IS_A_NEW_IP_ADDR_BRO = 'b', - - USRP2_CTRL_ID_GIVE_ME_YOUR_MAC_ADDR_BRO = 'm', - USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE = 'M', - USRP2_CTRL_ID_HERE_IS_A_NEW_MAC_ADDR_BRO = 'n', + USRP2_CTRL_ID_WAZZUP_BRO = 'a', + USRP2_CTRL_ID_WAZZUP_DUDE = 'A', USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO = 's', USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE = 'S', @@ -96,7 +91,6 @@ typedef struct{ _SINS_ uint32_t seq; union{ _SINS_ uint32_t ip_addr; - _SINS_ uint8_t mac_addr[6]; struct { _SINS_ uint8_t dev; _SINS_ uint8_t miso_edge; diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 7e62bedf0..9ae68d158 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -19,10 +19,11 @@ #include "usrp2_regs.hpp" #include #include +#include #include #include #include -#include //htonl and ntohl +#include #include using namespace uhd; @@ -129,30 +130,15 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ //handle the other props if (key.type() == typeid(std::string)){ if (key.as() == "mac-addr"){ - //setup the out data - usrp2_ctrl_data_t out_data; - out_data.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_MAC_ADDR_BRO); - - //send and recv - usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data); - UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE); - - //extract the address - val = mac_addr_t::from_bytes(in_data.data.mac_addr).to_string(); + byte_vector_t bytes = _iface->read_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_MAC_ADDR, 6); + val = mac_addr_t::from_bytes(bytes).to_string(); return; } if (key.as() == "ip-addr"){ - //setup the out data - usrp2_ctrl_data_t out_data; - out_data.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO); - - //send and recv - usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data); - UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE); - - //extract the address - val = boost::asio::ip::address_v4(ntohl(in_data.data.ip_addr)).to_string(); + boost::asio::ip::address_v4::bytes_type bytes; + std::copy(_iface->read_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_IP_ADDR, 4), bytes); + val = boost::asio::ip::address_v4(bytes).to_string(); return; } } @@ -223,27 +209,15 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){ //handle the other props if (key.type() == typeid(std::string)){ if (key.as() == "mac-addr"){ - //setup the out data - usrp2_ctrl_data_t out_data; - out_data.id = htonl(USRP2_CTRL_ID_HERE_IS_A_NEW_MAC_ADDR_BRO); - mac_addr_t mac_addr = mac_addr_t::from_string(val.as()); - std::copy(mac_addr.to_bytes(), mac_addr.to_bytes()+mac_addr_t::hlen, out_data.data.mac_addr); - - //send and recv - usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data); - UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE); + byte_vector_t bytes = mac_addr_t::from_string(val.as()).to_bytes(); + _iface->write_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_MAC_ADDR, bytes); return; } if (key.as() == "ip-addr"){ - //setup the out data - usrp2_ctrl_data_t out_data; - out_data.id = htonl(USRP2_CTRL_ID_HERE_IS_A_NEW_IP_ADDR_BRO); - out_data.data.ip_addr = htonl(boost::asio::ip::address_v4::from_string(val.as()).to_ulong()); - - //send and recv - usrp2_ctrl_data_t in_data = _iface->ctrl_send_and_recv(out_data); - UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE); + byte_vector_t bytes(4); + std::copy(boost::asio::ip::address_v4::from_string(val.as()).to_bytes(), bytes); + _iface->write_eeprom(I2C_ADDR_MBOARD, EE_MBOARD_IP_ADDR, bytes); return; } } diff --git a/host/lib/usrp/usrp2/usrp2_iface.hpp b/host/lib/usrp/usrp2/usrp2_iface.hpp index 7158c58d0..caf6623e2 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.hpp +++ b/host/lib/usrp/usrp2/usrp2_iface.hpp @@ -32,7 +32,14 @@ #define I2C_ADDR_MBOARD (I2C_DEV_EEPROM | 0x0) #define I2C_ADDR_TX_DB (I2C_DEV_EEPROM | 0x4) #define I2C_ADDR_RX_DB (I2C_DEV_EEPROM | 0x5) + +//////////////////////////////////////////////////////////////////////// +// EEPROM Layout //////////////////////////////////////////////////////////////////////// +#define EE_MBOARD_REV_LSB 0x00 //1 byte +#define EE_MBOARD_REV_MSB 0x01 //1 byte +#define EE_MBOARD_MAC_ADDR 0x02 //6 bytes +#define EE_MBOARD_IP_ADDR 0x0C //uint32, big-endian /*! * The usrp2 interface class: diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 5c1d7f9e3..2b7bdeea2 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -72,7 +72,7 @@ uhd::device_addrs_t usrp2::find(const device_addr_t &hint){ //send a hello control packet usrp2_ctrl_data_t ctrl_data_out; ctrl_data_out.proto_ver = htonl(USRP2_PROTO_VERSION); - ctrl_data_out.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO); + ctrl_data_out.id = htonl(USRP2_CTRL_ID_WAZZUP_BRO); udp_transport->send(boost::asio::buffer(&ctrl_data_out, sizeof(ctrl_data_out))); //loop and recieve until the timeout @@ -83,7 +83,7 @@ uhd::device_addrs_t usrp2::find(const device_addr_t &hint){ if (len >= sizeof(usrp2_ctrl_data_t)){ //handle the received data switch(ntohl(ctrl_data_in.id)){ - case USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE: + case USRP2_CTRL_ID_WAZZUP_DUDE: //make a boost asio ipv4 with the raw addr in host byte order boost::asio::ip::address_v4 ip_addr(ntohl(ctrl_data_in.data.ip_addr)); device_addr_t new_addr; -- cgit v1.2.3 From 11059ddbd6f5301f72299933321c35d00663dfe6 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 13 May 2010 17:35:09 -0700 Subject: fix to ad9777 dac control --- host/lib/ic_reg_maps/gen_ad9777_regs.py | 2 +- host/lib/usrp/usrp2/codec_ctrl.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'host/lib') diff --git a/host/lib/ic_reg_maps/gen_ad9777_regs.py b/host/lib/ic_reg_maps/gen_ad9777_regs.py index abb839f0f..690b15e24 100755 --- a/host/lib/ic_reg_maps/gen_ad9777_regs.py +++ b/host/lib/ic_reg_maps/gen_ad9777_regs.py @@ -59,7 +59,7 @@ pll_divide_ratio 3[0:1] 0 div1, div2, div4, div8 ## address 4 ######################################################################## pll_state 4[7] 0 off, on -auto_cp_control 4[6] 0 dis, enb +auto_cp_control 4[6] 0 auto, manual pll_cp_control 4[0:2] 0 50ua=0, 100ua=1, 200ua=2, 400ua=3, 800ua=7 ######################################################################## ## address 5 and 9 diff --git a/host/lib/usrp/usrp2/codec_ctrl.cpp b/host/lib/usrp/usrp2/codec_ctrl.cpp index d1e16881b..d698216ba 100644 --- a/host/lib/usrp/usrp2/codec_ctrl.cpp +++ b/host/lib/usrp/usrp2/codec_ctrl.cpp @@ -39,8 +39,8 @@ public: _ad9777_regs.filter_interp_rate = ad9777_regs_t::FILTER_INTERP_RATE_4X; _ad9777_regs.mix_mode = ad9777_regs_t::MIX_MODE_REAL; _ad9777_regs.pll_divide_ratio = ad9777_regs_t::PLL_DIVIDE_RATIO_DIV1; - _ad9777_regs.pll_state = ad9777_regs_t::PLL_STATE_OFF; - _ad9777_regs.auto_cp_control = ad9777_regs_t::AUTO_CP_CONTROL_ENB; + _ad9777_regs.pll_state = ad9777_regs_t::PLL_STATE_ON; + _ad9777_regs.auto_cp_control = ad9777_regs_t::AUTO_CP_CONTROL_AUTO; //I dac values _ad9777_regs.idac_fine_gain_adjust = 0; _ad9777_regs.idac_coarse_gain_adjust = 0xf; -- cgit v1.2.3 From abf2bc77f1880e34e206bd299fa0170f1bf9fe1d Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 13 May 2010 18:23:19 -0700 Subject: memcpy data when in custom io type --- host/lib/transport/convert_types.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'host/lib') diff --git a/host/lib/transport/convert_types.cpp b/host/lib/transport/convert_types.cpp index 8c3d6b17a..510d39454 100644 --- a/host/lib/transport/convert_types.cpp +++ b/host/lib/transport/convert_types.cpp @@ -115,10 +115,13 @@ void transport::convert_io_type_to_otw_type( switch(io_type.tid){ case io_type_t::COMPLEX_FLOAT32: host_floats_to_usrp2_items((boost::uint32_t *)otw_buff, (const fc32_t*)io_buff, num_samps); - break; + return; case io_type_t::COMPLEX_INT16: host_items_to_usrp2_items((boost::uint32_t *)otw_buff, (const boost::uint32_t*)io_buff, num_samps); - break; + return; + case io_type_t::CUSTOM_TYPE: + std::memcpy(otw_buff, io_buff, num_samps*io_type.size); + return; default: throw std::runtime_error(str(boost::format("convert_types: cannot handle type \"%c\"") % io_type.tid)); } @@ -135,10 +138,13 @@ void transport::convert_otw_type_to_io_type( switch(io_type.tid){ case io_type_t::COMPLEX_FLOAT32: usrp2_items_to_host_floats((fc32_t*)io_buff, (const boost::uint32_t *)otw_buff, num_samps); - break; + return; case io_type_t::COMPLEX_INT16: usrp2_items_to_host_items((boost::uint32_t*)io_buff, (const boost::uint32_t *)otw_buff, num_samps); - break; + return; + case io_type_t::CUSTOM_TYPE: + std::memcpy(io_buff, otw_buff, num_samps*io_type.size); + return; default: throw std::runtime_error(str(boost::format("convert_types: cannot handle type \"%c\"") % io_type.tid)); } -- cgit v1.2.3 From 695dd535d5a7419f467598a90c51c7e0f3d611e5 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 14 May 2010 13:02:04 -0700 Subject: added set freq with lo offset to simple usrp wrapper --- host/include/uhd/usrp/simple_usrp.hpp | 2 ++ host/lib/usrp/simple_usrp.cpp | 8 ++++++++ 2 files changed, 10 insertions(+) (limited to 'host/lib') diff --git a/host/include/uhd/usrp/simple_usrp.hpp b/host/include/uhd/usrp/simple_usrp.hpp index c4142b4e6..6ba1b90dd 100644 --- a/host/include/uhd/usrp/simple_usrp.hpp +++ b/host/include/uhd/usrp/simple_usrp.hpp @@ -112,6 +112,7 @@ public: virtual double get_rx_rate(void) = 0; virtual tune_result_t set_rx_freq(double freq) = 0; + virtual tune_result_t set_rx_freq(double freq, double lo_off) = 0; virtual freq_range_t get_rx_freq_range(void) = 0; virtual void set_rx_gain(float gain) = 0; @@ -131,6 +132,7 @@ public: virtual double get_tx_rate(void) = 0; virtual tune_result_t set_tx_freq(double freq) = 0; + virtual tune_result_t set_tx_freq(double freq, double lo_off) = 0; virtual freq_range_t get_tx_freq_range(void) = 0; virtual void set_tx_gain(float gain) = 0; diff --git a/host/lib/usrp/simple_usrp.cpp b/host/lib/usrp/simple_usrp.cpp index a8c104485..f4aa82669 100644 --- a/host/lib/usrp/simple_usrp.cpp +++ b/host/lib/usrp/simple_usrp.cpp @@ -121,6 +121,10 @@ public: return tune_rx_subdev_and_ddc(_rx_subdev, _rx_dsp, target_freq); } + tune_result_t set_rx_freq(double target_freq, double lo_off){ + return tune_rx_subdev_and_ddc(_rx_subdev, _rx_dsp, target_freq, lo_off); + } + freq_range_t get_rx_freq_range(void){ return _rx_subdev[SUBDEV_PROP_FREQ_RANGE].as(); } @@ -168,6 +172,10 @@ public: return tune_tx_subdev_and_duc(_tx_subdev, _tx_dsp, target_freq); } + tune_result_t set_tx_freq(double target_freq, double lo_off){ + return tune_tx_subdev_and_duc(_tx_subdev, _tx_dsp, target_freq, lo_off); + } + freq_range_t get_tx_freq_range(void){ return _tx_subdev[SUBDEV_PROP_FREQ_RANGE].as(); } -- cgit v1.2.3 From d20595a3fe9ba864d824c160c3db39fc7a3d1e7c Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 17 May 2010 09:52:43 -0700 Subject: calculate max samples per packet using otw type --- host/lib/usrp/usrp2/io_impl.cpp | 23 +++++++++++++++-------- host/lib/usrp/usrp2/mboard_impl.cpp | 2 +- host/lib/usrp/usrp2/usrp2_impl.cpp | 4 ++-- host/lib/usrp/usrp2/usrp2_impl.hpp | 27 +++++++++++++++++++-------- 4 files changed, 37 insertions(+), 19 deletions(-) (limited to 'host/lib') diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 7c9d003ce..de0c76eb1 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -31,10 +31,16 @@ namespace asio = boost::asio; * Helper Functions **********************************************************************/ void usrp2_impl::io_init(void){ - //setup otw type - _otw_type.width = 16; - _otw_type.shift = 0; - _otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN; + //setup rx otw type + _rx_otw_type.width = 16; + _rx_otw_type.shift = 0; + _rx_otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN; + + //setup tx otw type + _tx_otw_type.width = 16; + _tx_otw_type.shift = 0; + _tx_otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN; + //initially empty copy buffer _rx_copy_buff = asio::buffer("", 0); @@ -49,7 +55,8 @@ void usrp2_impl::io_init(void){ send_buff->done(sizeof(data)); //setup RX DSP regs - _iface->poke32(FR_RX_CTRL_NSAMPS_PER_PKT, _max_rx_samples_per_packet); + std::cout << "RX samples per packet: " << max_rx_samps_per_packet() << std::endl; + _iface->poke32(FR_RX_CTRL_NSAMPS_PER_PKT, max_rx_samps_per_packet()); _iface->poke32(FR_RX_CTRL_NCHANNELS, 1); _iface->poke32(FR_RX_CTRL_CLEAR_OVERRUN, 1); //reset _iface->poke32(FR_RX_CTRL_VRT_HEADER, 0 @@ -121,7 +128,7 @@ size_t usrp2_impl::send( boost::uint32_t *tx_mem = send_buff->cast(); size_t num_samps = std::min(std::min( asio::buffer_size(buff)/io_type.size, - size_t(_max_tx_samples_per_packet)), + size_t(max_tx_samps_per_packet())), send_buff->size()/io_type.size ); @@ -148,7 +155,7 @@ size_t usrp2_impl::send( //copy-convert the samples into the send buffer convert_io_type_to_otw_type( asio::buffer_cast(buff), io_type, - (void*)items, _otw_type, + (void*)items, _tx_otw_type, num_samps ); @@ -192,7 +199,7 @@ size_t usrp2_impl::recv( //copy-convert the samples from the recv buffer convert_otw_type_to_io_type( - (const void*)items, _otw_type, + (const void*)items, _rx_otw_type, asio::buffer_cast(buff), io_type, num_samps ); diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 9ae68d158..a10529102 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -111,7 +111,7 @@ void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ //issue the stream command _iface->poke32(FR_RX_CTRL_STREAM_CMD, FR_RX_CTRL_MAKE_CMD( - (inst_samps)? stream_cmd.num_samps : ((inst_chain)? _max_rx_samples_per_packet : 1), + (inst_samps)? stream_cmd.num_samps : ((inst_chain)? max_rx_samps_per_packet() : 1), (stream_cmd.stream_now)? 1 : 0, (inst_chain)? 1 : 0, (inst_reload)? 1 : 0 diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 2b7bdeea2..3b7156802 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -211,11 +211,11 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){ return; case DEVICE_PROP_MAX_RX_SAMPLES: - val = size_t(_max_rx_samples_per_packet); + val = max_rx_samps_per_packet(); return; case DEVICE_PROP_MAX_TX_SAMPLES: - val = size_t(_max_tx_samples_per_packet); + val = max_tx_samps_per_packet(); return; default: UHD_THROW_PROP_GET_ERROR(); diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index c5b6af810..e2d37e512 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -125,21 +125,32 @@ private: void recv_raw(uhd::rx_metadata_t &); uhd::dict _tx_stream_id_to_packet_seq; uhd::dict _rx_stream_id_to_packet_seq; + + /******************************************************************* + * Deal with the rx and tx packet sizes + ******************************************************************/ static const size_t _mtu = 1500; //FIXME we have no idea static const size_t _hdrs = (2 + 14 + 20 + 8); //size of headers (pad, eth, ip, udp) - static const size_t _max_rx_samples_per_packet = - (_mtu - _hdrs)/sizeof(boost::uint32_t) - - USRP2_HOST_RX_VRT_HEADER_WORDS32 - - USRP2_HOST_RX_VRT_TRAILER_WORDS32 + static const size_t _max_rx_bytes_per_packet = + _mtu - _hdrs - + USRP2_HOST_RX_VRT_HEADER_WORDS32*sizeof(boost::uint32_t) - + USRP2_HOST_RX_VRT_TRAILER_WORDS32*sizeof(boost::uint32_t) ; - static const size_t _max_tx_samples_per_packet = - (_mtu - _hdrs)/sizeof(boost::uint32_t) - - uhd::transport::vrt::max_header_words32 + static const size_t _max_tx_bytes_per_packet = + _mtu - _hdrs - + uhd::transport::vrt::max_header_words32*sizeof(boost::uint32_t) ; + size_t max_rx_samps_per_packet(void){ + return _max_rx_bytes_per_packet/(_rx_otw_type.width*2/8); + } + size_t max_tx_samps_per_packet(void){ + return _max_tx_bytes_per_packet/(_tx_otw_type.width*2/8); + } + uhd::transport::managed_recv_buffer::sptr _rx_smart_buff; boost::asio::const_buffer _rx_copy_buff; size_t _fragment_offset_in_samps; - uhd::otw_type_t _otw_type; + uhd::otw_type_t _rx_otw_type, _tx_otw_type; void io_init(void); //udp transports for control and data -- cgit v1.2.3 From 7823e08855f1fe48fbc014c37f822a9f22de19ef Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 17 May 2010 10:12:16 -0700 Subject: simplification of udp asio socket stuff --- host/include/uhd/transport/zero_copy.hpp | 12 ++--- host/lib/transport/udp_zero_copy_asio.cpp | 75 +++++++++++++++---------------- 2 files changed, 43 insertions(+), 44 deletions(-) (limited to 'host/lib') diff --git a/host/include/uhd/transport/zero_copy.hpp b/host/include/uhd/transport/zero_copy.hpp index 4fc1df9de..fdc5b141c 100644 --- a/host/include/uhd/transport/zero_copy.hpp +++ b/host/include/uhd/transport/zero_copy.hpp @@ -45,7 +45,7 @@ public: * Get the size of the underlying buffer. * \return the number of bytes */ - size_t size(void){ + size_t size(void) const{ return boost::asio::buffer_size(this->get()); } @@ -53,7 +53,7 @@ public: * Get a pointer to the underlying buffer. * \return a pointer into memory */ - template T cast(void){ + template T cast(void) const{ return boost::asio::buffer_cast(this->get()); } @@ -63,7 +63,7 @@ private: * The buffer has a reference to memory and a size. * \return a boost asio const buffer */ - virtual const boost::asio::const_buffer &get(void) = 0; + virtual const boost::asio::const_buffer &get(void) const = 0; }; /*! @@ -87,7 +87,7 @@ public: * Get the size of the underlying buffer. * \return the number of bytes */ - size_t size(void){ + size_t size(void) const{ return boost::asio::buffer_size(this->get()); } @@ -95,7 +95,7 @@ public: * Get a pointer to the underlying buffer. * \return a pointer into memory */ - template T cast(void){ + template T cast(void) const{ return boost::asio::buffer_cast(this->get()); } @@ -105,7 +105,7 @@ private: * The buffer has a reference to memory and a size. * \return a boost asio mutable buffer */ - virtual const boost::asio::mutable_buffer &get(void) = 0; + virtual const boost::asio::mutable_buffer &get(void) const = 0; }; /*! diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index ee44803f4..c26b39867 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -16,9 +16,9 @@ // #include +#include #include #include -#include #include #include @@ -26,65 +26,56 @@ using namespace uhd::transport; /*********************************************************************** * Managed receive buffer implementation for udp zero-copy asio: - * Frees the memory held by the const buffer on done. **********************************************************************/ class managed_recv_buffer_impl : public managed_recv_buffer{ public: managed_recv_buffer_impl(const boost::asio::const_buffer &buff) : _buff(buff){ - _done = false; + /* NOP */ } ~managed_recv_buffer_impl(void){ - if (not _done) this->done(); + /* NOP */ } void done(void){ - _done = true; - delete [] boost::asio::buffer_cast(_buff); + /* NOP */ } private: - const boost::asio::const_buffer &get(void){ + const boost::asio::const_buffer &get(void) const{ return _buff; } const boost::asio::const_buffer _buff; - bool _done; }; /*********************************************************************** * Managed send buffer implementation for udp zero-copy asio: - * Sends and frees the memory held by the mutable buffer on done. **********************************************************************/ class managed_send_buffer_impl : public managed_send_buffer{ public: managed_send_buffer_impl( const boost::asio::mutable_buffer &buff, boost::asio::ip::udp::socket *socket - ) : _buff(buff){ - _done = false; - _socket = socket; + ) : _buff(buff), _socket(socket){ + /* NOP */ } ~managed_send_buffer_impl(void){ - if (not _done) this->done(0); + /* NOP */ } void done(size_t num_bytes){ - _done = true; - boost::uint32_t *mem = boost::asio::buffer_cast(_buff); - _socket->send(boost::asio::buffer(mem, num_bytes)); - delete [] mem; + _socket->send(boost::asio::buffer(_buff, num_bytes)); } private: - const boost::asio::mutable_buffer &get(void){ + const boost::asio::mutable_buffer &get(void) const{ return _buff; } const boost::asio::mutable_buffer _buff; boost::asio::ip::udp::socket *_socket; - bool _done; }; /*********************************************************************** @@ -94,6 +85,8 @@ private: * However, it is not a true zero copy implementation as each * send and recv requires a copy operation to/from userspace. **********************************************************************/ +static const size_t max_buff_size = 2000; //assume max size on send and recv + class udp_zero_copy_impl : public udp_zero_copy{ public: //structors @@ -121,6 +114,11 @@ public: private: boost::asio::ip::udp::socket *_socket; boost::asio::io_service _io_service; + + //send and recv buffer memory (allocated once) + boost::uint8_t _send_mem[max_buff_size], _recv_mem[max_buff_size]; + + managed_send_buffer::sptr _send_buff; }; udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::string &port){ @@ -131,10 +129,25 @@ udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::strin boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), addr, port); boost::asio::ip::udp::endpoint receiver_endpoint = *resolver.resolve(query); - // Create, open, and connect the socket + // create, open, and connect the socket _socket = new boost::asio::ip::udp::socket(_io_service); _socket->open(boost::asio::ip::udp::v4()); _socket->connect(receiver_endpoint); + + // create the managed send buff (just once) + _send_buff = managed_send_buffer::sptr(new managed_send_buffer_impl( + boost::asio::buffer(_send_mem, max_buff_size), _socket + )); + + // set recv timeout + timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 100*1000; //100 ms + UHD_ASSERT_THROW(setsockopt( + _socket->native(), + SOL_SOCKET, SO_RCVTIMEO, + (timeval *)&tv, sizeof(timeval) + ) == 0); } udp_zero_copy_impl::~udp_zero_copy_impl(void){ @@ -142,31 +155,17 @@ udp_zero_copy_impl::~udp_zero_copy_impl(void){ } managed_recv_buffer::sptr udp_zero_copy_impl::get_recv_buff(void){ - //implement timeout through polling and sleeping - size_t available = 0; - boost::asio::deadline_timer timer(_socket->get_io_service()); - timer.expires_from_now(boost::posix_time::milliseconds(100)); - while (not ((available = _socket->available()) or timer.expires_from_now().is_negative())){ - boost::this_thread::sleep(boost::posix_time::milliseconds(1)); - } - - //receive only if data is available - boost::uint32_t *buff_mem = new boost::uint32_t[available/sizeof(boost::uint32_t)]; - if (available){ - available = _socket->receive(boost::asio::buffer(buff_mem, available)); - } + //call recv() with timeout option + size_t num_bytes = _socket->receive(boost::asio::buffer(_recv_mem, max_buff_size)); //create a new managed buffer to house the data return managed_recv_buffer::sptr( - new managed_recv_buffer_impl(boost::asio::buffer(buff_mem, available)) + new managed_recv_buffer_impl(boost::asio::buffer(_recv_mem, num_bytes)) ); } managed_send_buffer::sptr udp_zero_copy_impl::get_send_buff(void){ - boost::uint32_t *buff_mem = new boost::uint32_t[2000/sizeof(boost::uint32_t)]; - return managed_send_buffer::sptr( - new managed_send_buffer_impl(boost::asio::buffer(buff_mem, 2000), _socket) - ); + return _send_buff; } /*********************************************************************** -- cgit v1.2.3 From 7facfba666046f305086f754c9cebe1406ea54ad Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 17 May 2010 10:22:14 -0700 Subject: windows fix for setsockopt --- host/lib/transport/udp_zero_copy_asio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'host/lib') diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index c26b39867..e97bbf31c 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -146,7 +146,7 @@ udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::strin UHD_ASSERT_THROW(setsockopt( _socket->native(), SOL_SOCKET, SO_RCVTIMEO, - (timeval *)&tv, sizeof(timeval) + (const char *)&tv, sizeof(timeval) ) == 0); } -- cgit v1.2.3 From a6f7b02ae69eb4b0755f2805922eeb06d977c1ee Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 17 May 2010 11:01:42 -0700 Subject: automatic resize for small udp buffers --- host/lib/transport/udp_zero_copy_asio.cpp | 61 ++++++++++++++++++------------- 1 file changed, 35 insertions(+), 26 deletions(-) (limited to 'host/lib') diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index e97bbf31c..56ba391d3 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -89,6 +89,8 @@ static const size_t max_buff_size = 2000; //assume max size on send and recv class udp_zero_copy_impl : public udp_zero_copy{ public: + typedef boost::shared_ptr sptr; + //structors udp_zero_copy_impl(const std::string &addr, const std::string &port); ~udp_zero_copy_impl(void); @@ -97,18 +99,17 @@ public: managed_recv_buffer::sptr get_recv_buff(void); managed_send_buffer::sptr get_send_buff(void); - //resize - size_t resize_recv_buff(size_t num_bytes){ - boost::asio::socket_base::receive_buffer_size option(num_bytes); - _socket->set_option(option); + //manage buffer + template size_t get_buff_size(void){ + Opt option; _socket->get_option(option); return option.value(); } - size_t resize_send_buff(size_t num_bytes){ - boost::asio::socket_base::send_buffer_size option(num_bytes); + + template size_t resize_buff(size_t num_bytes){ + Opt option(num_bytes); _socket->set_option(option); - _socket->get_option(option); - return option.value(); + return get_buff_size(); } private: @@ -171,31 +172,39 @@ managed_send_buffer::sptr udp_zero_copy_impl::get_send_buff(void){ /*********************************************************************** * UDP zero copy make function **********************************************************************/ +template static inline void resize_buff_helper( + udp_zero_copy_impl::sptr udp_trans, + size_t target_size, + const std::string &name +){ + static const size_t min_buff_size = size_t(100e3); + + //resize the buffer if size was provided + if (target_size > 0){ + size_t actual_size = udp_trans->resize_buff(target_size); + if (target_size != actual_size) std::cout << boost::format( + "Target %s buffer size: %d\n" + "Actual %s byffer size: %d" + ) % name % target_size % name % actual_size << std::endl; + } + + //otherwise, ensure that the buffer is at least the minimum size + else if (udp_trans->get_buff_size() < min_buff_size){ + resize_buff_helper(udp_trans, min_buff_size, name); + } +} + udp_zero_copy::sptr udp_zero_copy::make( const std::string &addr, const std::string &port, size_t recv_buff_size, size_t send_buff_size ){ - boost::shared_ptr udp_trans(new udp_zero_copy_impl(addr, port)); - - //resize the recv buffer if size was provided - if (recv_buff_size > 0){ - size_t actual_bytes = udp_trans->resize_recv_buff(recv_buff_size); - if (recv_buff_size != actual_bytes) std::cout << boost::format( - "Target recv buffer size: %d\n" - "Actual recv byffer size: %d" - ) % recv_buff_size % actual_bytes << std::endl; - } + udp_zero_copy_impl::sptr udp_trans(new udp_zero_copy_impl(addr, port)); - //resize the send buffer if size was provided - if (send_buff_size > 0){ - size_t actual_bytes = udp_trans->resize_send_buff(send_buff_size); - if (send_buff_size != actual_bytes) std::cout << boost::format( - "Target send buffer size: %d\n" - "Actual send byffer size: %d" - ) % send_buff_size % actual_bytes << std::endl; - } + //call the helper to resize send and recv buffers + resize_buff_helper(udp_trans, recv_buff_size, "recv"); + resize_buff_helper (udp_trans, send_buff_size, "send"); return udp_trans; } -- cgit v1.2.3 From d9cc352ed14dbab04523f53e21f855b05c30eb3f Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 17 May 2010 13:22:26 -0700 Subject: work on generic packet handler (got rx working) --- host/lib/transport/vrt_packet_handler.hpp | 161 ++++++++++++++++++++++++++++++ host/lib/usrp/usrp2/io_impl.cpp | 95 ++---------------- host/lib/usrp/usrp2/usrp2_impl.hpp | 8 +- 3 files changed, 169 insertions(+), 95 deletions(-) create mode 100644 host/lib/transport/vrt_packet_handler.hpp (limited to 'host/lib') diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp new file mode 100644 index 000000000..a6161ef55 --- /dev/null +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -0,0 +1,161 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#ifndef INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP +#define INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace vrt_packet_handler{ + +/*********************************************************************** + * vrt packet handler for recv + **********************************************************************/ + struct recv_state{ + //init the expected seq number + size_t next_packet_seq; + + //state variables to handle fragments + uhd::transport::managed_recv_buffer::sptr managed_buff; + boost::asio::const_buffer copy_buff; + size_t fragment_offset_in_samps; + + recv_state(void){ + //first expected seq is zero + next_packet_seq = 0; + + //initially empty copy buffer + copy_buff = boost::asio::buffer("", 0); + } + }; + + typedef boost::function recv_cb_t; + + static inline void recv_cb_nop(uhd::transport::managed_recv_buffer::sptr){ + /* NOP */ + } + + static inline size_t recv( + recv_state &state, + const boost::asio::mutable_buffer &buff, + uhd::rx_metadata_t &metadata, + const uhd::io_type_t &io_type, + const uhd::otw_type_t &otw_type, + double tick_rate, + uhd::transport::zero_copy_if::sptr zc_iface, + size_t vrt_header_offset_words32 = 0, + const recv_cb_t& recv_cb = &recv_cb_nop + ){ + //////////////////////////////////////////////////////////////// + // Perform the recv + //////////////////////////////////////////////////////////////// + { + //perform a receive if no rx data is waiting to be copied + if (boost::asio::buffer_size(state.copy_buff) == 0){ + state.fragment_offset_in_samps = 0; + state.managed_buff = zc_iface->get_recv_buff(); + recv_cb(state.managed_buff); + } + //otherwise flag the metadata to show that is is a fragment + else{ + metadata = uhd::rx_metadata_t(); + goto vrt_recv_copy_convert; + } + } + + //////////////////////////////////////////////////////////////// + // Unpack the vrt header + //////////////////////////////////////////////////////////////// + { + size_t num_packet_words32 = state.managed_buff->size()/sizeof(boost::uint32_t); + if (num_packet_words32 <= vrt_header_offset_words32){ + state.copy_buff = boost::asio::buffer("", 0); + goto vrt_recv_copy_convert; //must exit here after setting the buffer + } + const boost::uint32_t *vrt_hdr = state.managed_buff->cast() + vrt_header_offset_words32; + size_t num_header_words32_out, num_payload_words32_out, packet_count_out; + uhd::transport::vrt::unpack( + metadata, //output + vrt_hdr, //input + num_header_words32_out, //output + num_payload_words32_out, //output + num_packet_words32, //input + packet_count_out, //output + tick_rate + ); + + //handle the packet count / sequence number + if (packet_count_out != state.next_packet_seq){ + std::cerr << "S" << (packet_count_out - state.next_packet_seq)%16; + } + state.next_packet_seq = (packet_count_out+1)%16; + + //setup the buffer to point to the data + state.copy_buff = boost::asio::buffer( + vrt_hdr + num_header_words32_out, + num_payload_words32_out*sizeof(boost::uint32_t) + ); + } + + //////////////////////////////////////////////////////////////// + // Perform copy-convert into buffer + //////////////////////////////////////////////////////////////// + vrt_recv_copy_convert:{ + size_t bytes_per_item = (otw_type.width * 2) / 8; + + //extract the number of samples available to copy + //and a pointer into the usrp2 received items memory + size_t bytes_available = boost::asio::buffer_size(state.copy_buff); + size_t num_samps = std::min( + boost::asio::buffer_size(buff)/io_type.size, + bytes_available/bytes_per_item + ); + + //setup the fragment flags and offset + metadata.more_fragments = boost::asio::buffer_size(buff)/io_type.size < num_samps; + metadata.fragment_offset = state.fragment_offset_in_samps; + state.fragment_offset_in_samps += num_samps; //set for next time + + //copy-convert the samples from the recv buffer + uhd::transport::convert_otw_type_to_io_type( + boost::asio::buffer_cast(state.copy_buff), otw_type, + boost::asio::buffer_cast(buff), io_type, + num_samps + ); + + //update the rx copy buffer to reflect the bytes copied + size_t bytes_copied = num_samps*bytes_per_item; + state.copy_buff = boost::asio::buffer( + boost::asio::buffer_cast(state.copy_buff) + bytes_copied, + bytes_available - bytes_copied + ); + + return num_samps; + } + } + +} //namespace vrt_packet_handler + +#endif /* INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP */ diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index de0c76eb1..389460fe8 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -41,13 +41,6 @@ void usrp2_impl::io_init(void){ _tx_otw_type.shift = 0; _tx_otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN; - - //initially empty copy buffer - _rx_copy_buff = asio::buffer("", 0); - - //init the expected rx seq number - _rx_stream_id_to_packet_seq[0] = 0; - //send a small data packet so the usrp2 knows the udp source port managed_send_buffer::sptr send_buff = _data_transport->get_send_buff(); boost::uint32_t data = htonl(USRP2_INVALID_VRT_HEADER); @@ -69,51 +62,6 @@ void usrp2_impl::io_init(void){ _iface->poke32(FR_RX_CTRL_VRT_TRAILER, 0); } -/*********************************************************************** - * Receive Raw Data - **********************************************************************/ -void usrp2_impl::recv_raw(rx_metadata_t &metadata){ - //do a receive - _rx_smart_buff = _data_transport->get_recv_buff(); - - //unpack the vrt header - size_t num_packet_words32 = _rx_smart_buff->size()/sizeof(boost::uint32_t); - if (num_packet_words32 == 0){ - _rx_copy_buff = boost::asio::buffer("", 0); - return; //must exit here after setting the buffer - } - const boost::uint32_t *vrt_hdr = _rx_smart_buff->cast(); - size_t num_header_words32_out, num_payload_words32_out, packet_count_out; - try{ - vrt::unpack( - metadata, //output - vrt_hdr, //input - num_header_words32_out, //output - num_payload_words32_out, //output - num_packet_words32, //input - packet_count_out, //output - get_master_clock_freq() - ); - }catch(const std::exception &e){ - std::cerr << "bad vrt header: " << e.what() << std::endl; - _rx_copy_buff = boost::asio::buffer("", 0); - return; //must exit here after setting the buffer - } - - //handle the packet count / sequence number - size_t expected_packet_count = _rx_stream_id_to_packet_seq[metadata.stream_id]; - if (packet_count_out != expected_packet_count){ - std::cerr << "S" << (packet_count_out - expected_packet_count)%16; - } - _rx_stream_id_to_packet_seq[metadata.stream_id] = (packet_count_out+1)%16; - - //setup the rx buffer to point to the data - _rx_copy_buff = asio::buffer( - vrt_hdr + num_header_words32_out, - num_payload_words32_out*sizeof(boost::uint32_t) - ); -} - /*********************************************************************** * Send Data **********************************************************************/ @@ -172,42 +120,11 @@ size_t usrp2_impl::recv( rx_metadata_t &metadata, const io_type_t &io_type ){ - //perform a receive if no rx data is waiting to be copied - if (asio::buffer_size(_rx_copy_buff) == 0){ - _fragment_offset_in_samps = 0; - recv_raw(metadata); - } - //otherwise flag the metadata to show that is is a fragment - else{ - metadata = rx_metadata_t(); - } - - //extract the number of samples available to copy - //and a pointer into the usrp2 received items memory - size_t bytes_to_copy = asio::buffer_size(_rx_copy_buff); - if (bytes_to_copy == 0) return 0; //nothing to receive - size_t num_samps = std::min( - asio::buffer_size(buff)/io_type.size, - bytes_to_copy/sizeof(boost::uint32_t) - ); - const boost::uint32_t *items = asio::buffer_cast(_rx_copy_buff); - - //setup the fragment flags and offset - metadata.more_fragments = asio::buffer_size(buff)/io_type.size < num_samps; - metadata.fragment_offset = _fragment_offset_in_samps; - _fragment_offset_in_samps += num_samps; //set for next time - - //copy-convert the samples from the recv buffer - convert_otw_type_to_io_type( - (const void*)items, _rx_otw_type, - asio::buffer_cast(buff), io_type, - num_samps - ); - - //update the rx copy buffer to reflect the bytes copied - _rx_copy_buff = asio::buffer( - items + num_samps, bytes_to_copy - num_samps*sizeof(boost::uint32_t) + return vrt_packet_handler::recv( + _packet_handler_recv_state, //last state of the recv handler + buff, metadata, //buffer to fill and samples metadata + io_type, _rx_otw_type, //input and output types to convert + get_master_clock_freq(), //master clock tick rate + _data_transport //zero copy interface ); - - return num_samps; } diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index e2d37e512..6958fc8ea 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -33,6 +33,7 @@ #include #include #include +#include "../../transport/vrt_packet_handler.hpp" /*! * Make a usrp2 dboard interface. @@ -121,10 +122,7 @@ private: codec_ctrl::sptr _codec_ctrl; serdes_ctrl::sptr _serdes_ctrl; - //the raw io interface (samples are in the usrp2 native format) - void recv_raw(uhd::rx_metadata_t &); uhd::dict _tx_stream_id_to_packet_seq; - uhd::dict _rx_stream_id_to_packet_seq; /******************************************************************* * Deal with the rx and tx packet sizes @@ -147,9 +145,7 @@ private: return _max_tx_bytes_per_packet/(_tx_otw_type.width*2/8); } - uhd::transport::managed_recv_buffer::sptr _rx_smart_buff; - boost::asio::const_buffer _rx_copy_buff; - size_t _fragment_offset_in_samps; + vrt_packet_handler::recv_state _packet_handler_recv_state; uhd::otw_type_t _rx_otw_type, _tx_otw_type; void io_init(void); -- cgit v1.2.3 From 101afd526de722b6d30381340a7ca8148aa9a6d7 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 17 May 2010 18:47:33 -0700 Subject: Created inline send vrt packer function that also handles fragmentation. --- host/include/uhd/device.hpp | 11 +- host/include/uhd/types/otw_type.hpp | 6 + host/lib/transport/vrt_packet_handler.hpp | 280 ++++++++++++++++++++++-------- host/lib/types.cpp | 4 + host/lib/usrp/usrp2/io_impl.cpp | 48 +---- host/lib/usrp/usrp2/usrp2_impl.hpp | 7 +- 6 files changed, 232 insertions(+), 124 deletions(-) (limited to 'host/lib') diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index ae75e6dc8..ecbe8c95c 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -80,12 +80,11 @@ public: * Send a buffer containing IF data with its metadata. * * Send handles fragmentation as follows: - * If the buffer has more samples than the maximum supported, - * the send method will send the maximum number of samples - * as supported by the transport and return the number sent. - * In this case, the end of burst flag will be forced to false. - * It is up to the caller to call send again on the un-sent - * portions of the buffer, until the buffer is exhausted. + * If the buffer has more samples than the maximum per packet, + * the send method will fragment the samples across several packets. + * Send will respect the burst flags when fragmenting to ensure + * that start of burst can only be set on the first fragment and + * that end of burst can only be set on the final fragment. * * This is a blocking call and will not return until the number * of samples returned have been read out of the buffer. diff --git a/host/include/uhd/types/otw_type.hpp b/host/include/uhd/types/otw_type.hpp index f10664584..8e3e65d78 100644 --- a/host/include/uhd/types/otw_type.hpp +++ b/host/include/uhd/types/otw_type.hpp @@ -55,6 +55,12 @@ namespace uhd{ BO_NOT_APPLICABLE = '|' } byteorder; + /*! + * Get the sample size of this otw type. + * \return the size of a sample in bytes + */ + size_t get_sample_size(void) const; + otw_type_t(void); }; diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index a6161ef55..cd0c89b05 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -57,6 +57,49 @@ namespace vrt_packet_handler{ /* NOP */ } + /******************************************************************* + * Unpack a received vrt header and set the copy buffer. + * - helper function for vrt_packet_handler::recv + ******************************************************************/ + static inline void _recv_helper( + recv_state &state, + uhd::rx_metadata_t &metadata, + double tick_rate, + size_t vrt_header_offset_words32 + ){ + size_t num_packet_words32 = state.managed_buff->size()/sizeof(boost::uint32_t); + if (num_packet_words32 <= vrt_header_offset_words32){ + state.copy_buff = boost::asio::buffer("", 0); + return; //must exit here after setting the buffer + } + const boost::uint32_t *vrt_hdr = state.managed_buff->cast() + vrt_header_offset_words32; + size_t num_header_words32_out, num_payload_words32_out, packet_count_out; + uhd::transport::vrt::unpack( + metadata, //output + vrt_hdr, //input + num_header_words32_out, //output + num_payload_words32_out, //output + num_packet_words32, //input + packet_count_out, //output + tick_rate + ); + + //handle the packet count / sequence number + if (packet_count_out != state.next_packet_seq){ + std::cerr << "S" << (packet_count_out - state.next_packet_seq)%16; + } + state.next_packet_seq = (packet_count_out+1)%16; + + //setup the buffer to point to the data + state.copy_buff = boost::asio::buffer( + vrt_hdr + num_header_words32_out, + num_payload_words32_out*sizeof(boost::uint32_t) + ); + } + + /******************************************************************* + * Recv vrt packets and copy convert the samples into the buffer. + ******************************************************************/ static inline size_t recv( recv_state &state, const boost::asio::mutable_buffer &buff, @@ -65,95 +108,184 @@ namespace vrt_packet_handler{ const uhd::otw_type_t &otw_type, double tick_rate, uhd::transport::zero_copy_if::sptr zc_iface, + //use these two params to handle a layer above vrt size_t vrt_header_offset_words32 = 0, const recv_cb_t& recv_cb = &recv_cb_nop ){ - //////////////////////////////////////////////////////////////// - // Perform the recv - //////////////////////////////////////////////////////////////// - { - //perform a receive if no rx data is waiting to be copied - if (boost::asio::buffer_size(state.copy_buff) == 0){ - state.fragment_offset_in_samps = 0; - state.managed_buff = zc_iface->get_recv_buff(); - recv_cb(state.managed_buff); - } - //otherwise flag the metadata to show that is is a fragment - else{ - metadata = uhd::rx_metadata_t(); - goto vrt_recv_copy_convert; - } - } + metadata = uhd::rx_metadata_t(); //init the metadata - //////////////////////////////////////////////////////////////// - // Unpack the vrt header - //////////////////////////////////////////////////////////////// - { - size_t num_packet_words32 = state.managed_buff->size()/sizeof(boost::uint32_t); - if (num_packet_words32 <= vrt_header_offset_words32){ - state.copy_buff = boost::asio::buffer("", 0); - goto vrt_recv_copy_convert; //must exit here after setting the buffer - } - const boost::uint32_t *vrt_hdr = state.managed_buff->cast() + vrt_header_offset_words32; - size_t num_header_words32_out, num_payload_words32_out, packet_count_out; - uhd::transport::vrt::unpack( - metadata, //output - vrt_hdr, //input - num_header_words32_out, //output - num_payload_words32_out, //output - num_packet_words32, //input - packet_count_out, //output - tick_rate + //perform a receive if no rx data is waiting to be copied + if (boost::asio::buffer_size(state.copy_buff) == 0){ + state.fragment_offset_in_samps = 0; + state.managed_buff = zc_iface->get_recv_buff(); + recv_cb(state.managed_buff); //callback before vrt unpack + _recv_helper( + state, metadata, tick_rate, vrt_header_offset_words32 ); + } - //handle the packet count / sequence number - if (packet_count_out != state.next_packet_seq){ - std::cerr << "S" << (packet_count_out - state.next_packet_seq)%16; - } - state.next_packet_seq = (packet_count_out+1)%16; + //extract the number of samples available to copy + size_t bytes_per_item = otw_type.get_sample_size(); + size_t bytes_available = boost::asio::buffer_size(state.copy_buff); + size_t num_samps = std::min( + boost::asio::buffer_size(buff)/io_type.size, + bytes_available/bytes_per_item + ); - //setup the buffer to point to the data - state.copy_buff = boost::asio::buffer( - vrt_hdr + num_header_words32_out, - num_payload_words32_out*sizeof(boost::uint32_t) - ); + //setup the fragment flags and offset + metadata.more_fragments = boost::asio::buffer_size(buff)/io_type.size < num_samps; + metadata.fragment_offset = state.fragment_offset_in_samps; + state.fragment_offset_in_samps += num_samps; //set for next call + + //copy-convert the samples from the recv buffer + uhd::transport::convert_otw_type_to_io_type( + boost::asio::buffer_cast(state.copy_buff), otw_type, + boost::asio::buffer_cast(buff), io_type, + num_samps + ); + + //update the rx copy buffer to reflect the bytes copied + size_t bytes_copied = num_samps*bytes_per_item; + state.copy_buff = boost::asio::buffer( + boost::asio::buffer_cast(state.copy_buff) + bytes_copied, + bytes_available - bytes_copied + ); + + return num_samps; + } + +/*********************************************************************** + * vrt packet handler for send + **********************************************************************/ + struct send_state{ + //init the expected seq number + size_t next_packet_seq; + + send_state(void){ + next_packet_seq = 0; } + }; - //////////////////////////////////////////////////////////////// - // Perform copy-convert into buffer - //////////////////////////////////////////////////////////////// - vrt_recv_copy_convert:{ - size_t bytes_per_item = (otw_type.width * 2) / 8; - - //extract the number of samples available to copy - //and a pointer into the usrp2 received items memory - size_t bytes_available = boost::asio::buffer_size(state.copy_buff); - size_t num_samps = std::min( - boost::asio::buffer_size(buff)/io_type.size, - bytes_available/bytes_per_item - ); + typedef boost::function send_cb_t; - //setup the fragment flags and offset - metadata.more_fragments = boost::asio::buffer_size(buff)/io_type.size < num_samps; - metadata.fragment_offset = state.fragment_offset_in_samps; - state.fragment_offset_in_samps += num_samps; //set for next time + static inline void send_cb_nop(uhd::transport::managed_send_buffer::sptr){ + /* NOP */ + } - //copy-convert the samples from the recv buffer - uhd::transport::convert_otw_type_to_io_type( - boost::asio::buffer_cast(state.copy_buff), otw_type, - boost::asio::buffer_cast(buff), io_type, - num_samps - ); + /******************************************************************* + * Pack a vrt header, copy-convert the data, and send it. + * - helper function for vrt_packet_handler::send + ******************************************************************/ + static inline void _send_helper( + send_state &state, + const void *send_mem, + size_t num_samps, + const uhd::tx_metadata_t &metadata, + const uhd::io_type_t &io_type, + const uhd::otw_type_t &otw_type, + double tick_rate, + uhd::transport::zero_copy_if::sptr zc_iface, + size_t vrt_header_offset_words32, + const send_cb_t& send_cb + ){ + //get a new managed send buffer + uhd::transport::managed_send_buffer::sptr send_buff = zc_iface->get_send_buff(); + boost::uint32_t *tx_mem = send_buff->cast() + vrt_header_offset_words32; + + size_t num_header_words32, num_packet_words32; + size_t packet_count = state.next_packet_seq++; - //update the rx copy buffer to reflect the bytes copied - size_t bytes_copied = num_samps*bytes_per_item; - state.copy_buff = boost::asio::buffer( - boost::asio::buffer_cast(state.copy_buff) + bytes_copied, - bytes_available - bytes_copied + //pack metadata into a vrt header + uhd::transport::vrt::pack( + metadata, //input + tx_mem, //output + num_header_words32, //output + num_samps, //input + num_packet_words32, //output + packet_count, //input + tick_rate + ); + + //copy-convert the samples into the send buffer + uhd::transport::convert_io_type_to_otw_type( + send_mem, io_type, + tx_mem + num_header_words32, otw_type, + num_samps + ); + + send_cb(send_buff); //callback after memory filled + + //commit the samples to the zero-copy interface + send_buff->done(num_packet_words32*sizeof(boost::uint32_t)); + } + + /******************************************************************* + * Send vrt packets and copy convert the samples into the buffer. + ******************************************************************/ + static inline size_t send( + send_state &state, + const boost::asio::const_buffer &buff, + const uhd::tx_metadata_t &metadata, + const uhd::io_type_t &io_type, + const uhd::otw_type_t &otw_type, + double tick_rate, + uhd::transport::zero_copy_if::sptr zc_iface, + size_t max_samples_per_packet, + //use these two params to handle a layer above vrt + size_t vrt_header_offset_words32 = 0, + const send_cb_t& send_cb = &send_cb_nop + ){ + + size_t total_num_samps = boost::asio::buffer_size(buff)/io_type.size; + + //special case: no fragmentation needed + if (total_num_samps <= max_samples_per_packet){ + _send_helper( + state, + boost::asio::buffer_cast(buff), + total_num_samps, + metadata, + io_type, otw_type, + tick_rate, + zc_iface, + vrt_header_offset_words32, + send_cb ); + return total_num_samps; + } - return num_samps; + //calculate constants for fragmentation + const size_t final_packet_samps = total_num_samps%max_samples_per_packet; + const size_t num_fragments = (total_num_samps+max_samples_per_packet-1)/max_samples_per_packet; + static const size_t first_fragment_index = 0; + const size_t final_fragment_index = num_fragments-1; + + //make a rw copy of the metadata to re-flag below + uhd::tx_metadata_t md(metadata); + + //loop through the following fragment indexes + for (size_t n = first_fragment_index; n <= final_fragment_index; n++){ + + //calculate new flags for the fragments + md.has_time_spec = md.has_time_spec and (n == first_fragment_index); + md.start_of_burst = md.start_of_burst and (n == first_fragment_index); + md.end_of_burst = md.end_of_burst and (n == final_fragment_index); + + //send the fragment with the helper function + _send_helper( + state, + boost::asio::buffer_cast(buff) + (n*max_samples_per_packet*io_type.size), + (n == final_fragment_index)?final_packet_samps:max_samples_per_packet, + md, + io_type, otw_type, + tick_rate, + zc_iface, + vrt_header_offset_words32, + send_cb + ); } + + return total_num_samps; } } //namespace vrt_packet_handler diff --git a/host/lib/types.cpp b/host/lib/types.cpp index 33eb550a1..87a2ad4ab 100644 --- a/host/lib/types.cpp +++ b/host/lib/types.cpp @@ -220,6 +220,10 @@ std::string mac_addr_t::to_string(void) const{ /*********************************************************************** * otw type **********************************************************************/ +size_t otw_type_t::get_sample_size(void) const{ + return (this->width * 2) / 8; +} + otw_type_t::otw_type_t(void){ width = 0; shift = 0; diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 389460fe8..b26dbb8bd 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -67,49 +67,17 @@ void usrp2_impl::io_init(void){ **********************************************************************/ size_t usrp2_impl::send( const asio::const_buffer &buff, - const tx_metadata_t &metadata_, + const tx_metadata_t &metadata, const io_type_t &io_type ){ - tx_metadata_t metadata = metadata_; //rw copy to change later - - transport::managed_send_buffer::sptr send_buff = _data_transport->get_send_buff(); - boost::uint32_t *tx_mem = send_buff->cast(); - size_t num_samps = std::min(std::min( - asio::buffer_size(buff)/io_type.size, - size_t(max_tx_samps_per_packet())), - send_buff->size()/io_type.size - ); - - //kill the end of burst flag if this is a fragment - if (asio::buffer_size(buff)/io_type.size < num_samps) - metadata.end_of_burst = false; - - size_t num_header_words32, num_packet_words32; - size_t packet_count = _tx_stream_id_to_packet_seq[metadata.stream_id]++; - - //pack metadata into a vrt header - vrt::pack( - metadata, //input - tx_mem, //output - num_header_words32, //output - num_samps, //input - num_packet_words32, //output - packet_count, //input - get_master_clock_freq() - ); - - boost::uint32_t *items = tx_mem + num_header_words32; //offset for data - - //copy-convert the samples into the send buffer - convert_io_type_to_otw_type( - asio::buffer_cast(buff), io_type, - (void*)items, _tx_otw_type, - num_samps + return vrt_packet_handler::send( + _packet_handler_send_state, //last state of the send handler + buff, metadata, //buffer to empty and samples metadata + io_type, _tx_otw_type, //input and output types to convert + get_master_clock_freq(), //master clock tick rate + _data_transport, //zero copy interface + max_tx_samps_per_packet() ); - - //send and return number of samples - send_buff->done(num_packet_words32*sizeof(boost::uint32_t)); - return num_samps; } /*********************************************************************** diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 6958fc8ea..f98aa1938 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -122,8 +122,6 @@ private: codec_ctrl::sptr _codec_ctrl; serdes_ctrl::sptr _serdes_ctrl; - uhd::dict _tx_stream_id_to_packet_seq; - /******************************************************************* * Deal with the rx and tx packet sizes ******************************************************************/ @@ -139,13 +137,14 @@ private: uhd::transport::vrt::max_header_words32*sizeof(boost::uint32_t) ; size_t max_rx_samps_per_packet(void){ - return _max_rx_bytes_per_packet/(_rx_otw_type.width*2/8); + return _max_rx_bytes_per_packet/_rx_otw_type.get_sample_size(); } size_t max_tx_samps_per_packet(void){ - return _max_tx_bytes_per_packet/(_tx_otw_type.width*2/8); + return _max_tx_bytes_per_packet/_tx_otw_type.get_sample_size(); } vrt_packet_handler::recv_state _packet_handler_recv_state; + vrt_packet_handler::send_state _packet_handler_send_state; uhd::otw_type_t _rx_otw_type, _tx_otw_type; void io_init(void); -- cgit v1.2.3 From 18f3f257145c4dcd981182221779550a7474488a Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 17 May 2010 22:24:14 -0700 Subject: Created config macro to force inline. --- host/CMakeLists.txt | 1 + host/include/uhd/config.hpp | 9 +++++++++ host/lib/transport/CMakeLists.txt | 1 + host/lib/transport/vrt_packet_handler.hpp | 13 +++++++------ 4 files changed, 18 insertions(+), 6 deletions(-) (limited to 'host/lib') diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index f2725e4b3..0b2d3f012 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -62,6 +62,7 @@ IF(UNIX) UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-ansi HAVE_ANSI) #only export symbols that are declared to be part of the uhd api: UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-fvisibility=hidden HAVE_VISIBILITY_HIDDEN) + UHD_ADD_OPTIONAL_CXX_COMPILER_FLAG(-O3 HAVE_O3) #have some optimizations ENDIF(UNIX) IF(WIN32) diff --git a/host/include/uhd/config.hpp b/host/include/uhd/config.hpp index 32eafc89b..fea95145c 100644 --- a/host/include/uhd/config.hpp +++ b/host/include/uhd/config.hpp @@ -76,4 +76,13 @@ #define UHD_LOCAL #endif // UHD_DLL +// Define force inline macro +#ifdef BOOST_MSVC + #define UHD_INLINE __forceinline +#elif defined(__GNUG__) && __GNUG__ >= 4 + #define UHD_INLINE inline __attribute__((always_inline)) +#else + #define UHD_INLINE inline +#endif + #endif /* INCLUDED_UHD_CONFIG_HPP */ diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt index a36f0fc03..ed8c35225 100644 --- a/host/lib/transport/CMakeLists.txt +++ b/host/lib/transport/CMakeLists.txt @@ -49,4 +49,5 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_SOURCE_DIR}/lib/transport/if_addrs.cpp ${CMAKE_SOURCE_DIR}/lib/transport/udp_simple.cpp ${CMAKE_SOURCE_DIR}/lib/transport/udp_zero_copy_asio.cpp + ${CMAKE_SOURCE_DIR}/lib/transport/vrt_packet_handler.hpp ) diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index cd0c89b05..f6353ef99 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -18,6 +18,7 @@ #ifndef INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP #define INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP +#include #include #include #include @@ -53,7 +54,7 @@ namespace vrt_packet_handler{ typedef boost::function recv_cb_t; - static inline void recv_cb_nop(uhd::transport::managed_recv_buffer::sptr){ + static UHD_INLINE void recv_cb_nop(uhd::transport::managed_recv_buffer::sptr){ /* NOP */ } @@ -61,7 +62,7 @@ namespace vrt_packet_handler{ * Unpack a received vrt header and set the copy buffer. * - helper function for vrt_packet_handler::recv ******************************************************************/ - static inline void _recv_helper( + static UHD_INLINE void _recv_helper( recv_state &state, uhd::rx_metadata_t &metadata, double tick_rate, @@ -100,7 +101,7 @@ namespace vrt_packet_handler{ /******************************************************************* * Recv vrt packets and copy convert the samples into the buffer. ******************************************************************/ - static inline size_t recv( + static UHD_INLINE size_t recv( recv_state &state, const boost::asio::mutable_buffer &buff, uhd::rx_metadata_t &metadata, @@ -168,7 +169,7 @@ namespace vrt_packet_handler{ typedef boost::function send_cb_t; - static inline void send_cb_nop(uhd::transport::managed_send_buffer::sptr){ + static UHD_INLINE void send_cb_nop(uhd::transport::managed_send_buffer::sptr){ /* NOP */ } @@ -176,7 +177,7 @@ namespace vrt_packet_handler{ * Pack a vrt header, copy-convert the data, and send it. * - helper function for vrt_packet_handler::send ******************************************************************/ - static inline void _send_helper( + static UHD_INLINE void _send_helper( send_state &state, const void *send_mem, size_t num_samps, @@ -222,7 +223,7 @@ namespace vrt_packet_handler{ /******************************************************************* * Send vrt packets and copy convert the samples into the buffer. ******************************************************************/ - static inline size_t send( + static UHD_INLINE size_t send( send_state &state, const boost::asio::const_buffer &buff, const uhd::tx_metadata_t &metadata, -- cgit v1.2.3 From 527630cc9d51b17c7cf5ab6ca257a78a28284f6d Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 17 May 2010 23:23:58 -0700 Subject: use static init lists for the types, some speedup for the fast path related ones, other changes are pointless --- host/include/uhd/types/mac_addr.hpp | 2 +- host/lib/types.cpp | 115 +++++++++++++++++++++--------------- 2 files changed, 68 insertions(+), 49 deletions(-) (limited to 'host/lib') diff --git a/host/include/uhd/types/mac_addr.hpp b/host/include/uhd/types/mac_addr.hpp index 034b6a348..0ced2e734 100644 --- a/host/include/uhd/types/mac_addr.hpp +++ b/host/include/uhd/types/mac_addr.hpp @@ -58,7 +58,7 @@ namespace uhd{ private: mac_addr_t(const byte_vector_t &bytes); //private constructor - byte_vector_t _bytes; //internal representation + const byte_vector_t _bytes; //internal representation }; } //namespace uhd diff --git a/host/lib/types.cpp b/host/lib/types.cpp index 87a2ad4ab..daf3be7f7 100644 --- a/host/lib/types.cpp +++ b/host/lib/types.cpp @@ -42,73 +42,89 @@ using namespace uhd; /*********************************************************************** * ranges **********************************************************************/ -gain_range_t::gain_range_t(float min_, float max_, float step_){ - min = min_; - max = max_; - step = step_; +gain_range_t::gain_range_t(float min, float max, float step): + min(min), + max(max), + step(step) +{ + /* NOP */ } -freq_range_t::freq_range_t(double min_, double max_){ - min = min_; - max = max_; +freq_range_t::freq_range_t(double min, double max): + min(min), + max(max) +{ + /* NOP */ } /*********************************************************************** * tune result **********************************************************************/ -tune_result_t::tune_result_t(void){ - target_inter_freq = 0.0; - actual_inter_freq = 0.0; - target_dsp_freq = 0.0; - actual_dsp_freq = 0.0; - spectrum_inverted = false; +tune_result_t::tune_result_t(void): + target_inter_freq(0.0), + actual_inter_freq(0.0), + target_dsp_freq(0.0), + actual_dsp_freq(0.0), + spectrum_inverted(false) +{ + /* NOP */ } /*********************************************************************** * clock config **********************************************************************/ -clock_config_t::clock_config_t(void){ - ref_source = REF_INT, - pps_source = PPS_INT, - pps_polarity = PPS_NEG; +clock_config_t::clock_config_t(void): + ref_source(REF_INT), + pps_source(PPS_INT), + pps_polarity(PPS_NEG) +{ + /* NOP */ } /*********************************************************************** * stream command **********************************************************************/ -stream_cmd_t::stream_cmd_t(const stream_mode_t &stream_mode_){ - stream_mode = stream_mode_; - stream_now = true; - num_samps = 0; +stream_cmd_t::stream_cmd_t(const stream_mode_t &stream_mode): + stream_mode(stream_mode), + num_samps(0), + stream_now(true) +{ + /* NOP */ } /*********************************************************************** * metadata **********************************************************************/ -rx_metadata_t::rx_metadata_t(void){ - stream_id = 0; - has_stream_id = false; - time_spec = time_spec_t(); - has_time_spec = false; - more_fragments = false; - fragment_offset = 0; +rx_metadata_t::rx_metadata_t(void): + has_stream_id(false), + stream_id(0), + has_time_spec(false), + time_spec(time_spec_t()), + more_fragments(false), + fragment_offset(0) +{ + /* NOP */ } -tx_metadata_t::tx_metadata_t(void){ - stream_id = 0; - has_stream_id = false; - time_spec = time_spec_t(); - has_time_spec = false; - start_of_burst = false; - end_of_burst = false; +tx_metadata_t::tx_metadata_t(void): + has_stream_id(false), + stream_id(0), + has_time_spec(false), + time_spec(time_spec_t()), + start_of_burst(false), + end_of_burst(false) +{ + /* NOP */ } /*********************************************************************** * time spec **********************************************************************/ -time_spec_t::time_spec_t(boost::uint32_t secs_, double nsecs_){ - secs = secs_; - nsecs = nsecs_; +time_spec_t::time_spec_t(boost::uint32_t secs, double nsecs): + secs(secs), + nsecs(nsecs) +{ + /* NOP */ } boost::uint32_t time_spec_t::get_ticks(double tick_rate) const{ @@ -165,9 +181,8 @@ std::string device_addr_t::to_string(void) const{ /*********************************************************************** * mac addr **********************************************************************/ -mac_addr_t::mac_addr_t(const byte_vector_t &bytes){ - UHD_ASSERT_THROW(bytes.size() == 6); - _bytes = bytes; +mac_addr_t::mac_addr_t(const byte_vector_t &bytes) : _bytes(bytes){ + UHD_ASSERT_THROW(_bytes.size() == 6); } mac_addr_t mac_addr_t::from_bytes(const byte_vector_t &bytes){ @@ -224,10 +239,12 @@ size_t otw_type_t::get_sample_size(void) const{ return (this->width * 2) / 8; } -otw_type_t::otw_type_t(void){ - width = 0; - shift = 0; - byteorder = BO_NATIVE; +otw_type_t::otw_type_t(void): + width(0), + shift(0), + byteorder(BO_NATIVE) +{ + /* NOP */ } /*********************************************************************** @@ -255,9 +272,11 @@ io_type_t::io_type_t(size_t size) /*********************************************************************** * serial **********************************************************************/ -spi_config_t::spi_config_t(edge_t edge){ - mosi_edge = edge; - miso_edge = edge; +spi_config_t::spi_config_t(edge_t edge): + mosi_edge(edge), + miso_edge(edge) +{ + /* NOP */ } void i2c_iface::write_eeprom( -- cgit v1.2.3 From eaa1508dcf6ff32496838f593ba4eb9eb1aee2ff Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 18 May 2010 12:34:04 -0700 Subject: Added send and recv modes to the device class and packet handler implementation. --- host/include/uhd/device.hpp | 33 +++++- host/lib/transport/vrt_packet_handler.hpp | 178 ++++++++++++++++++++---------- host/lib/usrp/usrp2/io_impl.cpp | 10 +- host/lib/usrp/usrp2/usrp2_impl.hpp | 14 ++- 4 files changed, 170 insertions(+), 65 deletions(-) (limited to 'host/lib') diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index ecbe8c95c..a76b34ee2 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -76,6 +76,16 @@ public: */ static sptr make(const device_addr_t &hint, size_t which = 0); + /*! + * Send modes for the device send routine. + */ + enum send_mode_t{ + //! Tells the send routine to send the entire buffer + SEND_MODE_FULL_BUFF = 0, + //! Tells the send routine to return after one packet + SEND_MODE_ONE_PACKET = 1 + }; + /*! * Send a buffer containing IF data with its metadata. * @@ -85,6 +95,7 @@ public: * Send will respect the burst flags when fragmenting to ensure * that start of burst can only be set on the first fragment and * that end of burst can only be set on the final fragment. + * Fragmentation only applies in the full buffer send mode. * * This is a blocking call and will not return until the number * of samples returned have been read out of the buffer. @@ -92,14 +103,26 @@ public: * \param buff a buffer pointing to some read-only memory * \param metadata data describing the buffer's contents * \param io_type the type of data loaded in the buffer + * \param send_mode tells send how to unload the buffer * \return the number of samples sent */ virtual size_t send( const boost::asio::const_buffer &buff, const tx_metadata_t &metadata, - const io_type_t &io_type + const io_type_t &io_type, + send_mode_t send_mode = SEND_MODE_ONE_PACKET ) = 0; + /*! + * Recv modes for the device recv routine. + */ + enum recv_mode_t{ + //! Tells the recv routine to recv the entire buffer + RECV_MODE_FULL_BUFF = 0, + //! Tells the recv routine to return after one packet + RECV_MODE_ONE_PACKET = 1 + }; + /*! * Receive a buffer containing IF data and its metadata. * @@ -122,15 +145,21 @@ public: * immediately when no packets are available to the transport layer, * and that the timeout duration is reasonably tuned for performance. * + * When using the full buffer recv mode, the metadata only applies + * to the first packet received and written into the recv buffer. + * Use the one packet recv mode to get per packet metadata. + * * \param buff the buffer to fill with IF data * \param metadata data to fill describing the buffer * \param io_type the type of data to fill into the buffer + * \param recv_mode tells recv how to load the buffer * \return the number of samples received */ virtual size_t recv( const boost::asio::mutable_buffer &buff, rx_metadata_t &metadata, - const io_type_t &io_type + const io_type_t &io_type, + recv_mode_t recv_mode = RECV_MODE_ONE_PACKET ) = 0; }; diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index f6353ef99..c857db1c4 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -19,6 +19,7 @@ #define INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP #include +#include #include #include #include @@ -60,9 +61,9 @@ namespace vrt_packet_handler{ /******************************************************************* * Unpack a received vrt header and set the copy buffer. - * - helper function for vrt_packet_handler::recv + * - helper function for vrt_packet_handler::_recv1 ******************************************************************/ - static UHD_INLINE void _recv_helper( + static UHD_INLINE void _recv1_helper( recv_state &state, uhd::rx_metadata_t &metadata, double tick_rate, @@ -99,28 +100,28 @@ namespace vrt_packet_handler{ } /******************************************************************* - * Recv vrt packets and copy convert the samples into the buffer. + * Recv data, unpack a vrt header, and copy-convert the data. + * - helper function for vrt_packet_handler::recv ******************************************************************/ - static UHD_INLINE size_t recv( + static UHD_INLINE size_t _recv1( recv_state &state, - const boost::asio::mutable_buffer &buff, + void *recv_mem, + size_t total_samps, uhd::rx_metadata_t &metadata, const uhd::io_type_t &io_type, const uhd::otw_type_t &otw_type, double tick_rate, uhd::transport::zero_copy_if::sptr zc_iface, //use these two params to handle a layer above vrt - size_t vrt_header_offset_words32 = 0, - const recv_cb_t& recv_cb = &recv_cb_nop + size_t vrt_header_offset_words32, + const recv_cb_t& recv_cb ){ - metadata = uhd::rx_metadata_t(); //init the metadata - //perform a receive if no rx data is waiting to be copied if (boost::asio::buffer_size(state.copy_buff) == 0){ state.fragment_offset_in_samps = 0; state.managed_buff = zc_iface->get_recv_buff(); recv_cb(state.managed_buff); //callback before vrt unpack - _recv_helper( + _recv1_helper( state, metadata, tick_rate, vrt_header_offset_words32 ); } @@ -128,21 +129,17 @@ namespace vrt_packet_handler{ //extract the number of samples available to copy size_t bytes_per_item = otw_type.get_sample_size(); size_t bytes_available = boost::asio::buffer_size(state.copy_buff); - size_t num_samps = std::min( - boost::asio::buffer_size(buff)/io_type.size, - bytes_available/bytes_per_item - ); + size_t num_samps = std::min(total_samps, bytes_available/bytes_per_item); //setup the fragment flags and offset - metadata.more_fragments = boost::asio::buffer_size(buff)/io_type.size < num_samps; + metadata.more_fragments = total_samps < num_samps; metadata.fragment_offset = state.fragment_offset_in_samps; state.fragment_offset_in_samps += num_samps; //set for next call //copy-convert the samples from the recv buffer uhd::transport::convert_otw_type_to_io_type( boost::asio::buffer_cast(state.copy_buff), otw_type, - boost::asio::buffer_cast(buff), io_type, - num_samps + recv_mem, io_type, num_samps ); //update the rx copy buffer to reflect the bytes copied @@ -155,6 +152,66 @@ namespace vrt_packet_handler{ return num_samps; } + /******************************************************************* + * Recv vrt packets and copy convert the samples into the buffer. + ******************************************************************/ + static UHD_INLINE size_t recv( + recv_state &state, + const boost::asio::mutable_buffer &buff, + uhd::rx_metadata_t &metadata, + uhd::device::recv_mode_t recv_mode, + const uhd::io_type_t &io_type, + const uhd::otw_type_t &otw_type, + double tick_rate, + uhd::transport::zero_copy_if::sptr zc_iface, + //use these two params to handle a layer above vrt + size_t vrt_header_offset_words32 = 0, + const recv_cb_t& recv_cb = &recv_cb_nop + ){ + metadata = uhd::rx_metadata_t(); //init the metadata + const size_t total_num_samps = boost::asio::buffer_size(buff)/io_type.size; + + switch(recv_mode){ + + //////////////////////////////////////////////////////////////// + case uhd::device::RECV_MODE_ONE_PACKET:{ + //////////////////////////////////////////////////////////////// + return _recv1( + state, + boost::asio::buffer_cast(buff), + total_num_samps, + metadata, + io_type, otw_type, + tick_rate, + zc_iface, + vrt_header_offset_words32, + recv_cb + ); + } + + //////////////////////////////////////////////////////////////// + case uhd::device::RECV_MODE_FULL_BUFF:{ + //////////////////////////////////////////////////////////////// + size_t num_samps = 0; + uhd::rx_metadata_t tmp_md; + while(num_samps < total_num_samps){ + num_samps += _recv1( + state, + boost::asio::buffer_cast(buff) + (num_samps*io_type.size), + total_num_samps - num_samps, + (num_samps == 0)? metadata : tmp_md, //only the first metadata gets kept + io_type, otw_type, + tick_rate, + zc_iface, + vrt_header_offset_words32, + recv_cb + ); + } + return total_num_samps; + } + }//switch(recv_mode) + } + /*********************************************************************** * vrt packet handler for send **********************************************************************/ @@ -177,7 +234,7 @@ namespace vrt_packet_handler{ * Pack a vrt header, copy-convert the data, and send it. * - helper function for vrt_packet_handler::send ******************************************************************/ - static UHD_INLINE void _send_helper( + static UHD_INLINE void _send1( send_state &state, const void *send_mem, size_t num_samps, @@ -227,6 +284,7 @@ namespace vrt_packet_handler{ send_state &state, const boost::asio::const_buffer &buff, const uhd::tx_metadata_t &metadata, + uhd::device::send_mode_t send_mode, const uhd::io_type_t &io_type, const uhd::otw_type_t &otw_type, double tick_rate, @@ -236,15 +294,17 @@ namespace vrt_packet_handler{ size_t vrt_header_offset_words32 = 0, const send_cb_t& send_cb = &send_cb_nop ){ - - size_t total_num_samps = boost::asio::buffer_size(buff)/io_type.size; - - //special case: no fragmentation needed - if (total_num_samps <= max_samples_per_packet){ - _send_helper( + const size_t total_num_samps = boost::asio::buffer_size(buff)/io_type.size; + switch(send_mode){ + + //////////////////////////////////////////////////////////////// + case uhd::device::SEND_MODE_ONE_PACKET:{ + //////////////////////////////////////////////////////////////// + size_t num_samps = std::min(total_num_samps, max_samples_per_packet); + _send1( state, boost::asio::buffer_cast(buff), - total_num_samps, + num_samps, metadata, io_type, otw_type, tick_rate, @@ -252,41 +312,45 @@ namespace vrt_packet_handler{ vrt_header_offset_words32, send_cb ); - return total_num_samps; + return num_samps; } - //calculate constants for fragmentation - const size_t final_packet_samps = total_num_samps%max_samples_per_packet; - const size_t num_fragments = (total_num_samps+max_samples_per_packet-1)/max_samples_per_packet; - static const size_t first_fragment_index = 0; - const size_t final_fragment_index = num_fragments-1; - - //make a rw copy of the metadata to re-flag below - uhd::tx_metadata_t md(metadata); - - //loop through the following fragment indexes - for (size_t n = first_fragment_index; n <= final_fragment_index; n++){ - - //calculate new flags for the fragments - md.has_time_spec = md.has_time_spec and (n == first_fragment_index); - md.start_of_burst = md.start_of_burst and (n == first_fragment_index); - md.end_of_burst = md.end_of_burst and (n == final_fragment_index); - - //send the fragment with the helper function - _send_helper( - state, - boost::asio::buffer_cast(buff) + (n*max_samples_per_packet*io_type.size), - (n == final_fragment_index)?final_packet_samps:max_samples_per_packet, - md, - io_type, otw_type, - tick_rate, - zc_iface, - vrt_header_offset_words32, - send_cb - ); + //////////////////////////////////////////////////////////////// + case uhd::device::SEND_MODE_FULL_BUFF:{ + //////////////////////////////////////////////////////////////// + //calculate constants for fragmentation + const size_t final_packet_samps = total_num_samps%max_samples_per_packet; + const size_t num_fragments = (total_num_samps+max_samples_per_packet-1)/max_samples_per_packet; + static const size_t first_fragment_index = 0; + const size_t final_fragment_index = num_fragments-1; + + //make a rw copy of the metadata to re-flag below + uhd::tx_metadata_t md(metadata); + + //loop through the following fragment indexes + for (size_t n = first_fragment_index; n <= final_fragment_index; n++){ + + //calculate new flags for the fragments + md.has_time_spec = md.has_time_spec and (n == first_fragment_index); + md.start_of_burst = md.start_of_burst and (n == first_fragment_index); + md.end_of_burst = md.end_of_burst and (n == final_fragment_index); + + //send the fragment with the helper function + _send1( + state, + boost::asio::buffer_cast(buff) + (n*max_samples_per_packet*io_type.size), + (n == final_fragment_index)?final_packet_samps:max_samples_per_packet, + md, + io_type, otw_type, + tick_rate, + zc_iface, + vrt_header_offset_words32, + send_cb + ); + } + return total_num_samps; } - - return total_num_samps; + }//switch(send_mode) } } //namespace vrt_packet_handler diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index b26dbb8bd..485cc2bd9 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -68,11 +68,12 @@ void usrp2_impl::io_init(void){ size_t usrp2_impl::send( const asio::const_buffer &buff, const tx_metadata_t &metadata, - const io_type_t &io_type + const io_type_t &io_type, + send_mode_t send_mode ){ return vrt_packet_handler::send( _packet_handler_send_state, //last state of the send handler - buff, metadata, //buffer to empty and samples metadata + buff, metadata, send_mode, //buffer to empty and samples metadata io_type, _tx_otw_type, //input and output types to convert get_master_clock_freq(), //master clock tick rate _data_transport, //zero copy interface @@ -86,11 +87,12 @@ size_t usrp2_impl::send( size_t usrp2_impl::recv( const asio::mutable_buffer &buff, rx_metadata_t &metadata, - const io_type_t &io_type + const io_type_t &io_type, + recv_mode_t recv_mode ){ return vrt_packet_handler::recv( _packet_handler_recv_state, //last state of the recv handler - buff, metadata, //buffer to fill and samples metadata + buff, metadata, recv_mode, //buffer to fill and samples metadata io_type, _rx_otw_type, //input and output types to convert get_master_clock_freq(), //master clock tick rate _data_transport //zero copy interface diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index f98aa1938..ad674f594 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -104,8 +104,18 @@ public: ~usrp2_impl(void); //the io interface - size_t send(const boost::asio::const_buffer &, const uhd::tx_metadata_t &, const uhd::io_type_t &); - size_t recv(const boost::asio::mutable_buffer &, uhd::rx_metadata_t &, const uhd::io_type_t &); + size_t send( + const boost::asio::const_buffer &, + const uhd::tx_metadata_t &, + const uhd::io_type_t &, + uhd::device::send_mode_t + ); + size_t recv( + const boost::asio::mutable_buffer &, + uhd::rx_metadata_t &, + const uhd::io_type_t &, + uhd::device::recv_mode_t + ); private: double get_master_clock_freq(void){ -- cgit v1.2.3 From 17c494b79a99d947a150cdbc582ba331aeb57786 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 18 May 2010 14:26:43 -0700 Subject: Added tx timed samples example. Added called to device to get max samples per packet. Removed device props that gave max samples per packet. --- host/examples/CMakeLists.txt | 4 ++ host/examples/rx_timed_samples.cpp | 13 +++-- host/examples/tx_timed_samples.cpp | 92 ++++++++++++++++++++++++++++++++++ host/include/uhd/device.hpp | 33 ++++++++---- host/include/uhd/usrp/device_props.hpp | 4 +- host/lib/usrp/usrp2/io_impl.cpp | 6 +-- host/lib/usrp/usrp2/mboard_impl.cpp | 2 +- host/lib/usrp/usrp2/usrp2_impl.cpp | 8 --- host/lib/usrp/usrp2/usrp2_impl.hpp | 12 ++--- 9 files changed, 138 insertions(+), 36 deletions(-) create mode 100644 host/examples/tx_timed_samples.cpp (limited to 'host/lib') diff --git a/host/examples/CMakeLists.txt b/host/examples/CMakeLists.txt index 242857625..a537c0901 100644 --- a/host/examples/CMakeLists.txt +++ b/host/examples/CMakeLists.txt @@ -18,3 +18,7 @@ ADD_EXECUTABLE(rx_timed_samples rx_timed_samples.cpp) TARGET_LINK_LIBRARIES(rx_timed_samples uhd) INSTALL(TARGETS rx_timed_samples RUNTIME DESTINATION ${PKG_DATA_DIR}/examples) + +ADD_EXECUTABLE(tx_timed_samples tx_timed_samples.cpp) +TARGET_LINK_LIBRARIES(tx_timed_samples uhd) +INSTALL(TARGETS tx_timed_samples RUNTIME DESTINATION ${PKG_DATA_DIR}/examples) diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp index 4b8774036..d2306c7c4 100644 --- a/host/examples/rx_timed_samples.cpp +++ b/host/examples/rx_timed_samples.cpp @@ -29,7 +29,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ std::string args; int seconds_in_future; size_t total_num_samps; - double rx_rate; + double rx_rate, freq; //setup the program options po::options_description desc("Allowed options"); @@ -39,10 +39,11 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ ("secs", po::value(&seconds_in_future)->default_value(3), "number of seconds in the future to receive") ("nsamps", po::value(&total_num_samps)->default_value(1000), "total number of samples to receive") ("rxrate", po::value(&rx_rate)->default_value(100e6/16), "rate of incoming samples") + ("freq", po::value(&freq)->default_value(0), "rf center frequency in Hz") ; po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); - po::notify(vm); + po::notify(vm); //print the help message if (vm.count("help")){ @@ -62,6 +63,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ sdev->set_rx_rate(rx_rate); std::cout << boost::format("Actual RX Rate: %f Msps...") % (sdev->get_rx_rate()/1e6) << std::endl; std::cout << boost::format("Setting device timestamp to 0...") << std::endl; + sdev->set_rx_freq(freq); sdev->set_time_now(uhd::time_spec_t(0)); //setup streaming @@ -78,10 +80,11 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ size_t num_acc_samps = 0; //number of accumulated samples while(num_acc_samps < total_num_samps){ uhd::rx_metadata_t md; - std::complex buff[1000]; + std::vector > buff(dev->get_max_recv_samps_per_packet()); size_t num_rx_samps = dev->recv( - boost::asio::buffer(buff, sizeof(buff)), - md, uhd::io_type_t::COMPLEX_FLOAT32 + boost::asio::buffer(buff), + md, uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::RECV_MODE_ONE_PACKET ); if (num_rx_samps == 0) continue; //wait for packets with contents diff --git a/host/examples/tx_timed_samples.cpp b/host/examples/tx_timed_samples.cpp new file mode 100644 index 000000000..6dee69cd5 --- /dev/null +++ b/host/examples/tx_timed_samples.cpp @@ -0,0 +1,92 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +#include +#include +#include +#include +#include +#include + +namespace po = boost::program_options; + +int UHD_SAFE_MAIN(int argc, char *argv[]){ + //variables to be set by po + std::string args; + int seconds_in_future; + size_t total_num_samps; + double tx_rate, freq; + float ampl; + + //setup the program options + po::options_description desc("Allowed options"); + desc.add_options() + ("help", "help message") + ("args", po::value(&args)->default_value(""), "simple uhd device address args") + ("secs", po::value(&seconds_in_future)->default_value(3), "number of seconds in the future to transmit") + ("nsamps", po::value(&total_num_samps)->default_value(1000), "total number of samples to transmit") + ("txrate", po::value(&tx_rate)->default_value(100e6/16), "rate of outgoing samples") + ("freq", po::value(&freq)->default_value(0), "rf center frequency in Hz") + ("ampl", po::value(&l)->default_value(0.3), "amplitude of each sample") + ; + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + + //print the help message + if (vm.count("help")){ + std::cout << boost::format("UHD TX Timed Samples %s") % desc << std::endl; + return ~0; + } + + //create a usrp device + std::cout << std::endl; + std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl; + uhd::usrp::simple_usrp::sptr sdev = uhd::usrp::simple_usrp::make(args); + uhd::device::sptr dev = sdev->get_device(); + std::cout << boost::format("Using Device: %s") % sdev->get_name() << std::endl; + + //set properties on the device + std::cout << boost::format("Setting TX Rate: %f Msps...") % (tx_rate/1e6) << std::endl; + sdev->set_tx_rate(tx_rate); + std::cout << boost::format("Actual TX Rate: %f Msps...") % (sdev->get_tx_rate()/1e6) << std::endl; + std::cout << boost::format("Setting device timestamp to 0...") << std::endl; + sdev->set_tx_freq(freq); + sdev->set_time_now(uhd::time_spec_t(0)); + + //data to send + std::vector > buff(total_num_samps, std::complex(ampl, ampl)); + uhd::tx_metadata_t md; + md.start_of_burst = true; + md.end_of_burst = true; + md.has_time_spec = true; + md.time_spec = uhd::time_spec_t(seconds_in_future); + + //send the entire buffer, let the driver handle fragmentation + size_t num_tx_samps = dev->send( + boost::asio::buffer(buff), + md, uhd::io_type_t::COMPLEX_FLOAT32, + uhd::device::SEND_MODE_FULL_BUFF + ); + std::cout << std::endl << boost::format("Sent %d samples") % num_tx_samps << std::endl; + + + //finished + std::cout << std::endl << "Done!" << std::endl << std::endl; + + return 0; +} diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index a76b34ee2..27b461184 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -86,6 +86,16 @@ public: SEND_MODE_ONE_PACKET = 1 }; + /*! + * Recv modes for the device recv routine. + */ + enum recv_mode_t{ + //! Tells the recv routine to recv the entire buffer + RECV_MODE_FULL_BUFF = 0, + //! Tells the recv routine to return after one packet + RECV_MODE_ONE_PACKET = 1 + }; + /*! * Send a buffer containing IF data with its metadata. * @@ -113,16 +123,6 @@ public: send_mode_t send_mode = SEND_MODE_ONE_PACKET ) = 0; - /*! - * Recv modes for the device recv routine. - */ - enum recv_mode_t{ - //! Tells the recv routine to recv the entire buffer - RECV_MODE_FULL_BUFF = 0, - //! Tells the recv routine to return after one packet - RECV_MODE_ONE_PACKET = 1 - }; - /*! * Receive a buffer containing IF data and its metadata. * @@ -161,6 +161,19 @@ public: const io_type_t &io_type, recv_mode_t recv_mode = RECV_MODE_ONE_PACKET ) = 0; + + /*! + * Get the maximum number of samples per packet on send. + * \return the number of samples + */ + virtual size_t get_max_send_samps_per_packet(void) const = 0; + + /*! + * Get the maximum number of samples per packet on recv. + * \return the number of samples + */ + virtual size_t get_max_recv_samps_per_packet(void) const = 0; + }; } //namespace uhd diff --git a/host/include/uhd/usrp/device_props.hpp b/host/include/uhd/usrp/device_props.hpp index b8f6f5cd4..983bcb672 100644 --- a/host/include/uhd/usrp/device_props.hpp +++ b/host/include/uhd/usrp/device_props.hpp @@ -31,9 +31,7 @@ namespace uhd{ namespace usrp{ enum device_prop_t{ DEVICE_PROP_NAME = 'n', //ro, std::string DEVICE_PROP_MBOARD = 'm', //ro, wax::obj - DEVICE_PROP_MBOARD_NAMES = 'M', //ro, prop_names_t - DEVICE_PROP_MAX_RX_SAMPLES = 'r', //ro, size_t - DEVICE_PROP_MAX_TX_SAMPLES = 't' //ro, size_t + DEVICE_PROP_MBOARD_NAMES = 'M' //ro, prop_names_t }; //////////////////////////////////////////////////////////////////////// diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 485cc2bd9..b6ab919e7 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -48,8 +48,8 @@ void usrp2_impl::io_init(void){ send_buff->done(sizeof(data)); //setup RX DSP regs - std::cout << "RX samples per packet: " << max_rx_samps_per_packet() << std::endl; - _iface->poke32(FR_RX_CTRL_NSAMPS_PER_PKT, max_rx_samps_per_packet()); + std::cout << "RX samples per packet: " << get_max_recv_samps_per_packet() << std::endl; + _iface->poke32(FR_RX_CTRL_NSAMPS_PER_PKT, get_max_recv_samps_per_packet()); _iface->poke32(FR_RX_CTRL_NCHANNELS, 1); _iface->poke32(FR_RX_CTRL_CLEAR_OVERRUN, 1); //reset _iface->poke32(FR_RX_CTRL_VRT_HEADER, 0 @@ -77,7 +77,7 @@ size_t usrp2_impl::send( io_type, _tx_otw_type, //input and output types to convert get_master_clock_freq(), //master clock tick rate _data_transport, //zero copy interface - max_tx_samps_per_packet() + get_max_send_samps_per_packet() ); } diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index a10529102..f17efd88e 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -111,7 +111,7 @@ void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ //issue the stream command _iface->poke32(FR_RX_CTRL_STREAM_CMD, FR_RX_CTRL_MAKE_CMD( - (inst_samps)? stream_cmd.num_samps : ((inst_chain)? max_rx_samps_per_packet() : 1), + (inst_samps)? stream_cmd.num_samps : ((inst_chain)? get_max_recv_samps_per_packet() : 1), (stream_cmd.stream_now)? 1 : 0, (inst_chain)? 1 : 0, (inst_reload)? 1 : 0 diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 3b7156802..af3ec216a 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -210,14 +210,6 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){ val = prop_names_t(1, ""); return; - case DEVICE_PROP_MAX_RX_SAMPLES: - val = max_rx_samps_per_packet(); - return; - - case DEVICE_PROP_MAX_TX_SAMPLES: - val = max_tx_samps_per_packet(); - return; - default: UHD_THROW_PROP_GET_ERROR(); } } diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index ad674f594..afea9683c 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -104,12 +104,18 @@ public: ~usrp2_impl(void); //the io interface + size_t get_max_send_samps_per_packet(void) const{ + return _max_tx_bytes_per_packet/_tx_otw_type.get_sample_size(); + } size_t send( const boost::asio::const_buffer &, const uhd::tx_metadata_t &, const uhd::io_type_t &, uhd::device::send_mode_t ); + size_t get_max_recv_samps_per_packet(void) const{ + return _max_rx_bytes_per_packet/_rx_otw_type.get_sample_size(); + } size_t recv( const boost::asio::mutable_buffer &, uhd::rx_metadata_t &, @@ -146,12 +152,6 @@ private: _mtu - _hdrs - uhd::transport::vrt::max_header_words32*sizeof(boost::uint32_t) ; - size_t max_rx_samps_per_packet(void){ - return _max_rx_bytes_per_packet/_rx_otw_type.get_sample_size(); - } - size_t max_tx_samps_per_packet(void){ - return _max_tx_bytes_per_packet/_tx_otw_type.get_sample_size(); - } vrt_packet_handler::recv_state _packet_handler_recv_state; vrt_packet_handler::send_state _packet_handler_send_state; -- cgit v1.2.3 From 4ea8822a50073b01ede9e0b0f7c8c713767ea1b8 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 18 May 2010 17:38:49 -0700 Subject: clock bypass divider fixes, forgot to move this part into the host --- host/lib/usrp/usrp2/clock_ctrl.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'host/lib') diff --git a/host/lib/usrp/usrp2/clock_ctrl.cpp b/host/lib/usrp/usrp2/clock_ctrl.cpp index db8d8a886..4c5207203 100644 --- a/host/lib/usrp/usrp2/clock_ctrl.cpp +++ b/host/lib/usrp/usrp2/clock_ctrl.cpp @@ -79,7 +79,9 @@ public: _ad9510_regs.power_down_lvds_cmos_out7 = enb? 0 : 1; _ad9510_regs.lvds_cmos_select_out7 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT7_CMOS; _ad9510_regs.output_level_lvds_out7 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT7_1_75MA; + _ad9510_regs.bypass_divider_out7 = 1; this->write_reg(0x43); + this->write_reg(0x57); this->update_regs(); } @@ -88,7 +90,9 @@ public: _ad9510_regs.power_down_lvds_cmos_out6 = enb? 0 : 1; _ad9510_regs.lvds_cmos_select_out6 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT6_CMOS; _ad9510_regs.output_level_lvds_out6 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT6_1_75MA; + _ad9510_regs.bypass_divider_out6 = 1; this->write_reg(0x42); + this->write_reg(0x55); this->update_regs(); } @@ -130,7 +134,9 @@ private: ad9510_regs_t::POWER_DOWN_LVPECL_OUT3_NORMAL : ad9510_regs_t::POWER_DOWN_LVPECL_OUT3_SAFE_PD; _ad9510_regs.output_level_lvpecl_out3 = ad9510_regs_t::OUTPUT_LEVEL_LVPECL_OUT3_810MV; + _ad9510_regs.bypass_divider_out3 = 1; this->write_reg(0x3F); + this->write_reg(0x4F); this->update_regs(); } @@ -139,7 +145,9 @@ private: _ad9510_regs.power_down_lvds_cmos_out4 = enb? 0 : 1; _ad9510_regs.lvds_cmos_select_out4 = ad9510_regs_t::LVDS_CMOS_SELECT_OUT4_LVDS; _ad9510_regs.output_level_lvds_out4 = ad9510_regs_t::OUTPUT_LEVEL_LVDS_OUT4_1_75MA; + _ad9510_regs.bypass_divider_out4 = 1; this->write_reg(0x40); + this->write_reg(0x51); this->update_regs(); } -- cgit v1.2.3 From bea1c582491d71bf90e240be345a32ba77028460 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 18 May 2010 18:03:27 -0700 Subject: tweaks to remove warning is msvc --- host/examples/tx_timed_samples.cpp | 2 +- host/lib/transport/vrt_packet_handler.hpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'host/lib') diff --git a/host/examples/tx_timed_samples.cpp b/host/examples/tx_timed_samples.cpp index 6dee69cd5..e9e0c785e 100644 --- a/host/examples/tx_timed_samples.cpp +++ b/host/examples/tx_timed_samples.cpp @@ -41,7 +41,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ ("nsamps", po::value(&total_num_samps)->default_value(1000), "total number of samples to transmit") ("txrate", po::value(&tx_rate)->default_value(100e6/16), "rate of outgoing samples") ("freq", po::value(&freq)->default_value(0), "rf center frequency in Hz") - ("ampl", po::value(&l)->default_value(0.3), "amplitude of each sample") + ("ampl", po::value(&l)->default_value(float(0.3)), "amplitude of each sample") ; po::variables_map vm; po::store(po::parse_command_line(argc, argv, desc), vm); diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index c857db1c4..5b73c82bf 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -28,6 +28,7 @@ #include #include #include +#include #include namespace vrt_packet_handler{ @@ -209,6 +210,8 @@ namespace vrt_packet_handler{ } return total_num_samps; } + + default: throw std::runtime_error("unknown recv mode"); }//switch(recv_mode) } @@ -350,6 +353,8 @@ namespace vrt_packet_handler{ } return total_num_samps; } + + default: throw std::runtime_error("unknown send mode"); }//switch(send_mode) } -- cgit v1.2.3 From 5aac700bc675c913b75b5fd791d9cf92949ceeea Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 18 May 2010 18:27:49 -0700 Subject: init values in dboards to remove gcc warnings --- host/lib/usrp/dboard/db_rfx.cpp | 4 ++-- host/lib/usrp/dboard/db_wbx.cpp | 2 +- host/lib/usrp/usrp2/CMakeLists.txt | 6 ++++++ 3 files changed, 9 insertions(+), 3 deletions(-) (limited to 'host/lib') diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp index bbc9716b1..3b3b96fad 100644 --- a/host/lib/usrp/dboard/db_rfx.cpp +++ b/host/lib/usrp/dboard/db_rfx.cpp @@ -258,8 +258,8 @@ double rfx_xcvr::set_lo_freq( (8, adf4360_regs_t::BAND_SELECT_CLOCK_DIV_8) ; - double actual_freq, ref_freq = this->get_iface()->get_clock_rate(unit); - int R, BS, P, B, A; + double actual_freq=0, ref_freq = this->get_iface()->get_clock_rate(unit); + int R=0, BS=0, P=0, B=0, A=0; /* * The goal here to to loop though possible R dividers, diff --git a/host/lib/usrp/dboard/db_wbx.cpp b/host/lib/usrp/dboard/db_wbx.cpp index 2a8a3a9f2..81edf7a11 100644 --- a/host/lib/usrp/dboard/db_wbx.cpp +++ b/host/lib/usrp/dboard/db_wbx.cpp @@ -303,7 +303,7 @@ double wbx_xcvr::set_lo_freq( double actual_freq, pfd_freq; double ref_freq = this->get_iface()->get_clock_rate(unit); - int R, BS, N, FRAC, MOD; + 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; diff --git a/host/lib/usrp/usrp2/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt index fee67dff9..99d0b8bdd 100644 --- a/host/lib/usrp/usrp2/CMakeLists.txt +++ b/host/lib/usrp/usrp2/CMakeLists.txt @@ -19,13 +19,19 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/clock_ctrl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/clock_ctrl.hpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_ctrl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/codec_ctrl.hpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dboard_impl.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dboard_iface.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/dsp_impl.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/io_impl.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/mboard_impl.cpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/serdes_ctrl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/serdes_ctrl.hpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_iface.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_iface.hpp ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_impl.cpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_impl.hpp + ${CMAKE_SOURCE_DIR}/lib/usrp/usrp2/usrp2_regs.hpp ) -- cgit v1.2.3 From fd28cd7056867ec1ab81f7fb408c382e110ddaa1 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 19 May 2010 11:56:50 -0700 Subject: break recv loop on timeout --- host/lib/transport/vrt_packet_handler.hpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'host/lib') diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index 5b73c82bf..ab1b7e16c 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -193,22 +193,24 @@ namespace vrt_packet_handler{ //////////////////////////////////////////////////////////////// case uhd::device::RECV_MODE_FULL_BUFF:{ //////////////////////////////////////////////////////////////// - size_t num_samps = 0; + size_t accum_num_samps = 0; uhd::rx_metadata_t tmp_md; - while(num_samps < total_num_samps){ - num_samps += _recv1( + while(accum_num_samps < total_num_samps){ + size_t num_samps = _recv1( state, boost::asio::buffer_cast(buff) + (num_samps*io_type.size), total_num_samps - num_samps, - (num_samps == 0)? metadata : tmp_md, //only the first metadata gets kept + (accum_num_samps == 0)? metadata : tmp_md, //only the first metadata gets kept io_type, otw_type, tick_rate, zc_iface, vrt_header_offset_words32, recv_cb ); + if (num_samps == 0) break; //had a recv timeout or error, break loop + accum_num_samps += num_samps; } - return total_num_samps; + return accum_num_samps; } default: throw std::runtime_error("unknown recv mode"); -- cgit v1.2.3 From b46c5abe79dcd70cd21f7dce56f29e962237d6c9 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 19 May 2010 15:09:31 -0700 Subject: Fixed some bugs in the send and recv full buffer modes. Dealing with samples counts, metadata flags, etc.. --- host/lib/transport/convert_types.cpp | 9 +++++---- host/lib/transport/vrt_packet_handler.hpp | 14 +++++++------- 2 files changed, 12 insertions(+), 11 deletions(-) (limited to 'host/lib') diff --git a/host/lib/transport/convert_types.cpp b/host/lib/transport/convert_types.cpp index 510d39454..43503025a 100644 --- a/host/lib/transport/convert_types.cpp +++ b/host/lib/transport/convert_types.cpp @@ -15,6 +15,7 @@ // along with this program. If not, see . // +#include #include #include #include //endianness conversion @@ -49,7 +50,7 @@ static const bool is_big_endian = true; static const bool is_big_endian = false; #endif -static inline void host_floats_to_usrp2_items( +static UHD_INLINE void host_floats_to_usrp2_items( boost::uint32_t *usrp2_items, const fc32_t *host_floats, size_t num_samps @@ -62,7 +63,7 @@ static inline void host_floats_to_usrp2_items( unrolled_loop(host_floats_to_usrp2_items_i, num_samps); } -static inline void usrp2_items_to_host_floats( +static UHD_INLINE void usrp2_items_to_host_floats( fc32_t *host_floats, const boost::uint32_t *usrp2_items, size_t num_samps @@ -76,7 +77,7 @@ static inline void usrp2_items_to_host_floats( unrolled_loop(usrp2_items_to_host_floats_i, num_samps); } -static inline void host_items_to_usrp2_items( +static UHD_INLINE void host_items_to_usrp2_items( boost::uint32_t *usrp2_items, const boost::uint32_t *host_items, size_t num_samps @@ -90,7 +91,7 @@ static inline void host_items_to_usrp2_items( } } -static inline void usrp2_items_to_host_items( +static UHD_INLINE void usrp2_items_to_host_items( boost::uint32_t *host_items, const boost::uint32_t *usrp2_items, size_t num_samps diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index ab1b7e16c..2a7f995a1 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -198,8 +198,8 @@ namespace vrt_packet_handler{ while(accum_num_samps < total_num_samps){ size_t num_samps = _recv1( state, - boost::asio::buffer_cast(buff) + (num_samps*io_type.size), - total_num_samps - num_samps, + boost::asio::buffer_cast(buff) + (accum_num_samps*io_type.size), + total_num_samps - accum_num_samps, (accum_num_samps == 0)? metadata : tmp_md, //only the first metadata gets kept io_type, otw_type, tick_rate, @@ -300,6 +300,7 @@ namespace vrt_packet_handler{ const send_cb_t& send_cb = &send_cb_nop ){ const size_t total_num_samps = boost::asio::buffer_size(buff)/io_type.size; + if (total_num_samps <= max_samples_per_packet) send_mode = uhd::device::SEND_MODE_ONE_PACKET; switch(send_mode){ //////////////////////////////////////////////////////////////// @@ -324,7 +325,6 @@ namespace vrt_packet_handler{ case uhd::device::SEND_MODE_FULL_BUFF:{ //////////////////////////////////////////////////////////////// //calculate constants for fragmentation - const size_t final_packet_samps = total_num_samps%max_samples_per_packet; const size_t num_fragments = (total_num_samps+max_samples_per_packet-1)/max_samples_per_packet; static const size_t first_fragment_index = 0; const size_t final_fragment_index = num_fragments-1; @@ -336,15 +336,15 @@ namespace vrt_packet_handler{ for (size_t n = first_fragment_index; n <= final_fragment_index; n++){ //calculate new flags for the fragments - md.has_time_spec = md.has_time_spec and (n == first_fragment_index); - md.start_of_burst = md.start_of_burst and (n == first_fragment_index); - md.end_of_burst = md.end_of_burst and (n == final_fragment_index); + md.has_time_spec = metadata.has_time_spec and (n == first_fragment_index); + md.start_of_burst = metadata.start_of_burst and (n == first_fragment_index); + md.end_of_burst = metadata.end_of_burst and (n == final_fragment_index); //send the fragment with the helper function _send1( state, boost::asio::buffer_cast(buff) + (n*max_samples_per_packet*io_type.size), - (n == final_fragment_index)?final_packet_samps:max_samples_per_packet, + (n == final_fragment_index)?(total_num_samps%max_samples_per_packet):max_samples_per_packet, md, io_type, otw_type, tick_rate, -- cgit v1.2.3 From fb000993e185a182386101a8bafd880d7c4b2bf0 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 19 May 2010 16:23:31 -0700 Subject: rfx dboard code minor refactor to look more like xcvr2450 code --- host/lib/usrp/dboard/db_rfx.cpp | 116 +++++++++++++++++++++++++--------------- 1 file changed, 73 insertions(+), 43 deletions(-) (limited to 'host/lib') diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp index 3b3b96fad..7bfd14943 100644 --- a/host/lib/usrp/dboard/db_rfx.cpp +++ b/host/lib/usrp/dboard/db_rfx.cpp @@ -15,8 +15,6 @@ // along with this program. If not, see . // -static const bool rfx_debug = false; - // IO Pin functions #define POWER_IO (1 << 7) // Low enables power supply #define ANTSW_IO (1 << 6) // On TX DB, 0 = TX, 1 = RX, on RX DB 0 = main ant, 1 = RX2 @@ -56,10 +54,23 @@ using namespace uhd::usrp; using namespace boost::assign; /*********************************************************************** - * The RFX series of dboards + * The RFX Series constants **********************************************************************/ -static const float _max_rx_pga0_gain = 45; +static const bool rfx_debug = false; + +static const prop_names_t rfx_tx_antennas = list_of("TX/RX"); + +static const prop_names_t rfx_rx_antennas = list_of("TX/RX")("RX2"); +static const uhd::dict rfx_tx_gain_ranges; //empty + +static const uhd::dict rfx_rx_gain_ranges = map_list_of + ("PGA0", gain_range_t(0, 45, float(0.022))) +; + +/*********************************************************************** + * The RFX series of dboards + **********************************************************************/ class rfx_xcvr : public xcvr_dboard_base{ public: rfx_xcvr( @@ -85,6 +96,10 @@ private: void set_rx_lo_freq(double freq); void set_tx_lo_freq(double freq); void set_rx_ant(const std::string &ant); + void set_tx_ant(const std::string &ant); + void set_rx_gain(float gain, const std::string &name); + void set_tx_gain(float gain, const std::string &name); + void set_rx_pga0_gain(float gain); /*! @@ -189,19 +204,11 @@ rfx_xcvr::~rfx_xcvr(void){ } /*********************************************************************** - * Helper Methods + * Antenna Handling **********************************************************************/ -void rfx_xcvr::set_rx_lo_freq(double freq){ - _rx_lo_freq = set_lo_freq(dboard_iface::UNIT_RX, freq); -} - -void rfx_xcvr::set_tx_lo_freq(double freq){ - _tx_lo_freq = set_lo_freq(dboard_iface::UNIT_TX, freq); -} - void rfx_xcvr::set_rx_ant(const std::string &ant){ //validate input - UHD_ASSERT_THROW(ant == "TX/RX" or ant == "RX2"); + assert_has(rfx_rx_antennas, ant, "rfx rx antenna name"); //set the rx atr regs that change with antenna setting this->get_iface()->set_atr_reg( @@ -213,22 +220,51 @@ void rfx_xcvr::set_rx_ant(const std::string &ant){ _rx_ant = ant; } -void rfx_xcvr::set_rx_pga0_gain(float gain){ - //clip the input - gain = std::clip(gain, 0, _max_rx_pga0_gain); +void rfx_xcvr::set_tx_ant(const std::string &ant){ + assert_has(rfx_tx_antennas, ant, "rfx tx antenna name"); + //only one antenna option, do nothing +} + +/*********************************************************************** + * Gain Handling + **********************************************************************/ +void rfx_xcvr::set_tx_gain(float, const std::string &name){ + assert_has(rfx_tx_gain_ranges.keys(), name, "rfx tx gain name"); + UHD_ASSERT_THROW(false); //no gains to set +} + +void rfx_xcvr::set_rx_gain(float gain, const std::string &name){ + assert_has(rfx_rx_gain_ranges.keys(), name, "rfx rx gain name"); + if(name == "PGA0"){ + this->set_rx_pga0_gain(gain); + } + else UHD_ASSERT_THROW(false); +} - //voltage level constants +void rfx_xcvr::set_rx_pga0_gain(float gain){ + //voltage level constants (negative slope) static const float max_volts = float(.2), min_volts = float(1.2); - static const float slope = (max_volts-min_volts)/_max_rx_pga0_gain; + static const float slope = (max_volts-min_volts)/45; //calculate the voltage for the aux dac - float dac_volts = gain*slope + min_volts; + float dac_volts = std::clip(gain*slope + min_volts, max_volts, min_volts); //write the new voltage to the aux dac this->get_iface()->write_aux_dac(dboard_iface::UNIT_RX, 1, dac_volts); - //shadow the setting (does not account for precision loss) - _rx_pga0_gain = gain; + //shadow the actual gain setting + _rx_pga0_gain = (dac_volts - min_volts)/slope; +} + +/*********************************************************************** + * Tuning + **********************************************************************/ +void rfx_xcvr::set_rx_lo_freq(double freq){ + _rx_lo_freq = set_lo_freq(dboard_iface::UNIT_RX, freq); +} + +void rfx_xcvr::set_tx_lo_freq(double freq){ + _tx_lo_freq = set_lo_freq(dboard_iface::UNIT_TX, freq); } double rfx_xcvr::set_lo_freq( @@ -364,12 +400,12 @@ void rfx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){ return; case SUBDEV_PROP_GAIN_RANGE: - UHD_ASSERT_THROW(name == "PGA0"); - val = gain_range_t(0, _max_rx_pga0_gain, float(0.022)); + assert_has(rfx_rx_gain_ranges.keys(), name, "rfx rx gain name"); + val = rfx_rx_gain_ranges[name]; return; case SUBDEV_PROP_GAIN_NAMES: - val = prop_names_t(1, "PGA0"); + val = prop_names_t(rfx_rx_gain_ranges.keys()); return; case SUBDEV_PROP_FREQ: @@ -384,10 +420,8 @@ void rfx_xcvr::rx_get(const wax::obj &key_, wax::obj &val){ val = _rx_ant; return; - case SUBDEV_PROP_ANTENNA_NAMES:{ - prop_names_t ants = list_of("TX/RX")("RX2"); - val = ants; - } + case SUBDEV_PROP_ANTENNA_NAMES: + val = rfx_rx_antennas; return; case SUBDEV_PROP_QUADRATURE: @@ -422,16 +456,15 @@ void rfx_xcvr::rx_set(const wax::obj &key_, const wax::obj &val){ switch(key.as()){ case SUBDEV_PROP_FREQ: - set_rx_lo_freq(val.as()); + this->set_rx_lo_freq(val.as()); return; case SUBDEV_PROP_GAIN: - UHD_ASSERT_THROW(name == "PGA0"); - set_rx_pga0_gain(val.as()); + this->set_rx_gain(val.as(), name); return; case SUBDEV_PROP_ANTENNA: - set_rx_ant(val.as()); + this->set_rx_ant(val.as()); return; default: UHD_THROW_PROP_SET_ERROR(); @@ -456,15 +489,13 @@ void rfx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){ return; case SUBDEV_PROP_GAIN: - val = float(0); - return; - case SUBDEV_PROP_GAIN_RANGE: - val = gain_range_t(0, 0, 0); + assert_has(rfx_tx_gain_ranges.keys(), name, "rfx tx gain name"); + //no controllable tx gains, will not get here return; case SUBDEV_PROP_GAIN_NAMES: - val = prop_names_t(); //empty + val = prop_names_t(rfx_tx_gain_ranges.keys()); return; case SUBDEV_PROP_FREQ: @@ -480,7 +511,7 @@ void rfx_xcvr::tx_get(const wax::obj &key_, wax::obj &val){ return; case SUBDEV_PROP_ANTENNA_NAMES: - val = prop_names_t(1, "TX/RX"); + val = rfx_tx_antennas; return; case SUBDEV_PROP_QUADRATURE: @@ -515,16 +546,15 @@ void rfx_xcvr::tx_set(const wax::obj &key_, const wax::obj &val){ switch(key.as()){ case SUBDEV_PROP_FREQ: - set_tx_lo_freq(val.as()); + this->set_tx_lo_freq(val.as()); return; case SUBDEV_PROP_GAIN: - //no gains to set! + this->set_tx_gain(val.as(), name); return; case SUBDEV_PROP_ANTENNA: - //its always set to tx/rx, so we only allow this value - UHD_ASSERT_THROW(val.as() == "TX/RX"); + this->set_tx_ant(val.as()); return; default: UHD_THROW_PROP_SET_ERROR(); -- cgit v1.2.3 From 76ce1d824a41beacdb5bd603549c9b0e3f64d98f Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 21 May 2010 17:30:05 -0700 Subject: mac os x card burner support and documentation notes --- host/docs/build.rst | 31 ++++++++++++++++++++++++++----- host/docs/usrp2.rst | 2 +- host/lib/transport/gen_vrt.py | 2 +- host/utils/usrp2_card_burner.py | 21 +++++++++++++++++++++ 4 files changed, 49 insertions(+), 7 deletions(-) (limited to 'host/lib') diff --git a/host/docs/build.rst b/host/docs/build.rst index d28682764..f5a8dac8d 100644 --- a/host/docs/build.rst +++ b/host/docs/build.rst @@ -8,9 +8,14 @@ UHD - Build Guide Build Dependencies ------------------------------------------------------------------------ -**Unix Notes:** +**Linux Notes:** The dependencies can be acquired through the package manager. +**Mac OS X Notes:** +Install the "Xcode Developer Tools" to get the build tools (gcc and make). +Use MacPorts to get the Boost and Cheetah dependencies. +Other dependencies can be downloaded as dmg installers from the web. + **Windows Notes:** The dependencies can be acquired through installable exe files. Usually, the windows installer can be found on the project's website. @@ -27,12 +32,13 @@ or install msysgit from http://code.google.com/p/msysgit/downloads/list ^^^^^^^^^^^^^^^^ C++ ^^^^^^^^^^^^^^^^ -On unix, this is GCC 4.0 and above. On windows, this is MSVC 2008. +On Unix, this is GCC 4.0 and above. On Windows, this is MSVC 2008. Other compilers have not been tested yet or confirmed working. ^^^^^^^^^^^^^^^^ CMake ^^^^^^^^^^^^^^^^ +* **Purpose:** generates project build files * **Version:** at least 2.8 * **Required for:** build time * **Download URL:** http://www.cmake.org/cmake/resources/software.html @@ -40,6 +46,7 @@ CMake ^^^^^^^^^^^^^^^^ Boost ^^^^^^^^^^^^^^^^ +* **Purpose:** C++ library * **Version:** at least 3.6 unix, at least 4.0 windows * **Required for:** build time + run time * **Download URL:** http://www.boost.org/users/download/ @@ -48,13 +55,15 @@ Boost ^^^^^^^^^^^^^^^^ Python ^^^^^^^^^^^^^^^^ +* **Purpose:** used by Cheetah and utility scripts * **Version:** at least 2.6 -* **Required for:** build time +* **Required for:** build time + run time utility scripts * **Download URL:** http://www.python.org/download/ ^^^^^^^^^^^^^^^^ Cheetah ^^^^^^^^^^^^^^^^ +* **Purpose:** source code generation * **Version:** at least 2.0 * **Required for:** build time * **Download URL:** http://www.cheetahtemplate.org/download.html @@ -63,9 +72,17 @@ Cheetah ^^^^^^^^^^^^^^^^ Doxygen ^^^^^^^^^^^^^^^^ +* **Purpose:** generates html api documentation * **Required for:** build time (optional) * **Download URL:** http://www.stack.nl/~dimitri/doxygen/download.html#latestsrc +^^^^^^^^^^^^^^^^ +Docutils +^^^^^^^^^^^^^^^^ +* **Purpose:** generates html user manual +* **Required for:** build time (optional) +* **Download URL:** http://docutils.sourceforge.net/ + ------------------------------------------------------------------------ Build Instructions (Unix) ------------------------------------------------------------------------ @@ -80,7 +97,7 @@ Generate Makefiles with cmake cd build cmake ../ -For a custom prefix, use: cmake -DCMAKE_INSTALL_PREFIX= ../ +For a custom prefix, use: cmake -DCMAKE_INSTALL_PREFIX= ../ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Build and install @@ -92,11 +109,15 @@ Build and install sudo make install ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Setup the library path +Setup the library path (Linux) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Make sure that libuhd.so is in your LD_LIBRARY_PATH or add it to /etc/ld.so.conf and make sure to run sudo ldconfig +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Setup the library path (Mac OS X) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Make sure that libuhd.dylib is in your DYLD_LIBRARY_PATH ------------------------------------------------------------------------ Build Instructions (Windows) diff --git a/host/docs/usrp2.rst b/host/docs/usrp2.rst index c4a7aa64f..1bd95cefa 100644 --- a/host/docs/usrp2.rst +++ b/host/docs/usrp2.rst @@ -50,7 +50,7 @@ you could overwrite your hard drive. Make sure that --dev= specifies the SD card Use the *--list* option to get a list of possible raw devices. The list result will filter out disk partitions and devices too large to be the sd card. -The list option has not yet been implemented on macosx. +The list option has been implemented on Linux, Mac OS X, and Windows. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use the card burner tool (unix) diff --git a/host/lib/transport/gen_vrt.py b/host/lib/transport/gen_vrt.py index 9a57c83c3..c34ffb198 100755 --- a/host/lib/transport/gen_vrt.py +++ b/host/lib/transport/gen_vrt.py @@ -57,7 +57,7 @@ void vrt::pack( size_t packet_count, //input double tick_rate //input ){ - boost::uint32_t vrt_hdr_flags; + boost::uint32_t vrt_hdr_flags = 0; boost::uint8_t pred = 0; if (metadata.has_stream_id) pred |= $hex($sid_p); diff --git a/host/utils/usrp2_card_burner.py b/host/utils/usrp2_card_burner.py index 60aca9133..d47a4f5f4 100755 --- a/host/utils/usrp2_card_burner.py +++ b/host/utils/usrp2_card_burner.py @@ -22,6 +22,7 @@ import subprocess import urllib import optparse import os +import re ######################################################################## # constants @@ -106,6 +107,26 @@ def get_raw_device_hints(): return sorted(set(devs)) + #################################################################### + # Platform Mac OS X: parse diskutil list and info commands + #################################################################### + if platform.system() == 'Darwin': + devs = map(lambda d: d.split()[0], filter(lambda l: l.startswith('/dev'), command('diskutil', 'list').splitlines())) + def output_to_info(output): + return dict([map(str.strip, pair.lower().split(':')) for pair in filter(lambda l: ':' in l, output.splitlines())]) + def is_dev_valid(dev): + info = output_to_info(command('diskutil', 'info', dev)) + try: + if info.has_key('internal'): assert info['internal'] == 'no' + if info.has_key('ejectable'): assert info['ejectable'] == 'yes' + if info.has_key('total size'): + size_match = re.match('^.*\((\d+)\s*bytes\).*$', info['total size']) + if size_match: assert int(size_match.groups()[0]) <= MAX_SD_CARD_SIZE + return True + except: return False + + return sorted(set(filter(is_dev_valid, devs))) + #################################################################### # Platform Others: #################################################################### -- cgit v1.2.3 From 830e34fe30737432a5bfa4b19cc4bad5b4e425ee Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 24 May 2010 11:47:53 -0700 Subject: fix for time64 register write order --- host/lib/usrp/usrp2/mboard_impl.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'host/lib') diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index f17efd88e..a2aeadf16 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -83,13 +83,15 @@ void usrp2_impl::update_clock_config(void){ } void usrp2_impl::set_time_spec(const time_spec_t &time_spec, bool now){ - //set ticks and seconds - _iface->poke32(FR_TIME64_SECS, time_spec.secs); + //set the ticks _iface->poke32(FR_TIME64_TICKS, time_spec.get_ticks(get_master_clock_freq())); - //set the register to latch it all in + //set the flags register boost::uint32_t imm_flags = (now)? FRF_TIME64_LATCH_NOW : FRF_TIME64_LATCH_NEXT_PPS; _iface->poke32(FR_TIME64_IMM, imm_flags); + + //set the seconds (latches in all 3 registers) + _iface->poke32(FR_TIME64_SECS, time_spec.secs); } void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ -- cgit v1.2.3 From 71169b8e030d984220eadde83c4b40481f97cf6b Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 24 May 2010 14:38:25 -0700 Subject: Added timeout error message to timed samples example. Added try catch to recv helper because vrt unpack can throw. --- host/examples/rx_timed_samples.cpp | 4 ++++ host/lib/transport/vrt_packet_handler.hpp | 11 ++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) (limited to 'host/lib') diff --git a/host/examples/rx_timed_samples.cpp b/host/examples/rx_timed_samples.cpp index d2306c7c4..64da260d5 100644 --- a/host/examples/rx_timed_samples.cpp +++ b/host/examples/rx_timed_samples.cpp @@ -86,6 +86,10 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){ md, uhd::io_type_t::COMPLEX_FLOAT32, uhd::device::RECV_MODE_ONE_PACKET ); + if (num_rx_samps == 0 and num_acc_samps > 0){ + std::cout << "Got timeout before all samples received, possible packet loss, exiting loop..." << std::endl; + break; + } if (num_rx_samps == 0) continue; //wait for packets with contents std::cout << boost::format("Got packet: %u samples, %u secs, %u nsecs") diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index 2a7f995a1..81420b39e 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -122,9 +122,14 @@ namespace vrt_packet_handler{ state.fragment_offset_in_samps = 0; state.managed_buff = zc_iface->get_recv_buff(); recv_cb(state.managed_buff); //callback before vrt unpack - _recv1_helper( - state, metadata, tick_rate, vrt_header_offset_words32 - ); + try{ + _recv1_helper( + state, metadata, tick_rate, vrt_header_offset_words32 + ); + }catch(const std::exception &e){ + std::cerr << "Error (recv): " << e.what() << std::endl; + return 0; + } } //extract the number of samples available to copy -- cgit v1.2.3 From 39943a5b0c3c210babfd6e62711ea4bf3133866b Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 24 May 2010 16:31:23 -0700 Subject: Added support to set GPIO pins from dboard interface: write gpio and set pin control (atr or gpio) Added property to get dboard interface from the dboard obj. --- host/include/uhd/usrp/dboard_iface.hpp | 22 ++++++++++++++++++++-- host/include/uhd/usrp/dboard_props.hpp | 3 ++- host/lib/usrp/dboard/db_rfx.cpp | 4 +++- host/lib/usrp/dboard/db_wbx.cpp | 4 +++- host/lib/usrp/dboard/db_xcvr2450.cpp | 4 +++- host/lib/usrp/dboard_manager.cpp | 3 ++- host/lib/usrp/usrp2/dboard_iface.cpp | 34 ++++++++++++++++++++++++++-------- host/lib/usrp/usrp2/dboard_impl.cpp | 12 +++++++++--- host/lib/usrp/usrp2/usrp2_impl.hpp | 1 + host/lib/usrp/usrp2/usrp2_regs.hpp | 2 +- 10 files changed, 70 insertions(+), 19 deletions(-) (limited to 'host/lib') diff --git a/host/include/uhd/usrp/dboard_iface.hpp b/host/include/uhd/usrp/dboard_iface.hpp index 1214a1a2f..7ecfcd3c0 100644 --- a/host/include/uhd/usrp/dboard_iface.hpp +++ b/host/include/uhd/usrp/dboard_iface.hpp @@ -67,23 +67,41 @@ public: */ virtual float read_aux_adc(unit_t unit, int which_adc) = 0; + /*! + * Set a daughterboard output pin control source. + * By default, the outputs are all GPIO controlled. + * + * \param unit which unit rx or tx + * \param value 16-bits, 0=GPIO controlled, 1=ATR controlled + */ + virtual void set_pin_ctrl(unit_t unit, boost::uint16_t value) = 0; + /*! * Set a daughterboard ATR register. * * \param unit which unit rx or tx * \param reg which ATR register to set - * \param value 16-bits, 0=FPGA output low, 1=FPGA output high + * \param value 16-bits, 0=ATR output low, 1=ATR output high */ virtual void set_atr_reg(unit_t unit, atr_reg_t reg, boost::uint16_t value) = 0; /*! * Set daughterboard GPIO data direction register. + * By default, the GPIO pins are all inputs. * * \param unit which unit rx or tx - * \param value 16-bits, 0=FPGA input, 1=FPGA output + * \param value 16-bits, 0=GPIO input, 1=GPIO output */ virtual void set_gpio_ddr(unit_t unit, boost::uint16_t value) = 0; + /*! + * Read daughterboard GPIO pin values. + * + * \param unit which unit rx or tx + * \param value 16-bits, 0=GPIO output low, 1=GPIO output high + */ + virtual void write_gpio(unit_t unit, boost::uint16_t value) = 0; + /*! * Read daughterboard GPIO pin values. * diff --git a/host/include/uhd/usrp/dboard_props.hpp b/host/include/uhd/usrp/dboard_props.hpp index 0208a6c2c..4d5c5efbd 100644 --- a/host/include/uhd/usrp/dboard_props.hpp +++ b/host/include/uhd/usrp/dboard_props.hpp @@ -30,7 +30,8 @@ namespace uhd{ namespace usrp{ DBOARD_PROP_SUBDEV = 's', //ro, wax::obj DBOARD_PROP_SUBDEV_NAMES = 'S', //ro, prop_names_t DBOARD_PROP_USED_SUBDEVS = 'u', //ro, prop_names_t - DBOARD_PROP_DBOARD_ID = 'i' //rw, dboard_id_t + DBOARD_PROP_DBOARD_ID = 'i', //rw, dboard_id_t + DBOARD_PROP_DBOARD_IFACE = 'f' //ro, dboard_iface::sptr //DBOARD_PROP_CODEC //ro, wax::obj //----> not sure, dont have to deal with yet }; diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp index 7bfd14943..89e707718 100644 --- a/host/lib/usrp/dboard/db_rfx.cpp +++ b/host/lib/usrp/dboard/db_rfx.cpp @@ -176,8 +176,10 @@ rfx_xcvr::rfx_xcvr( this->get_iface()->set_clock_enabled(dboard_iface::UNIT_TX, true); this->get_iface()->set_clock_enabled(dboard_iface::UNIT_RX, true); - //set the gpio directions + //set the gpio directions and atr controls (identically) boost::uint16_t output_enables = POWER_IO | ANTSW_IO | MIXER_IO; + this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_TX, output_enables); + this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, output_enables); this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, output_enables); this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, output_enables); diff --git a/host/lib/usrp/dboard/db_wbx.cpp b/host/lib/usrp/dboard/db_wbx.cpp index 81edf7a11..23654860f 100644 --- a/host/lib/usrp/dboard/db_wbx.cpp +++ b/host/lib/usrp/dboard/db_wbx.cpp @@ -164,7 +164,9 @@ wbx_xcvr::wbx_xcvr( this->get_iface()->set_clock_enabled(dboard_iface::UNIT_TX, true); this->get_iface()->set_clock_enabled(dboard_iface::UNIT_RX, true); - //set the gpio directions + //set the gpio directions and atr controls (identically) + this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_TX, TXIO_MASK); + this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, RXIO_MASK); this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, TXIO_MASK); this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, RXIO_MASK); if (wbx_debug) std::cerr << boost::format( diff --git a/host/lib/usrp/dboard/db_xcvr2450.cpp b/host/lib/usrp/dboard/db_xcvr2450.cpp index 3472229f4..d4d5f184e 100644 --- a/host/lib/usrp/dboard/db_xcvr2450.cpp +++ b/host/lib/usrp/dboard/db_xcvr2450.cpp @@ -169,7 +169,9 @@ xcvr2450::xcvr2450(ctor_args_t args) : xcvr_dboard_base(args){ //enable only the clocks we need this->get_iface()->set_clock_enabled(dboard_iface::UNIT_TX, true); - //set the gpio directions + //set the gpio directions and atr controls (identically) + this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_TX, TXIO_MASK); + this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, RXIO_MASK); this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, TXIO_MASK); this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, RXIO_MASK); diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp index 8161727e5..01352039e 100644 --- a/host/lib/usrp/dboard_manager.cpp +++ b/host/lib/usrp/dboard_manager.cpp @@ -298,7 +298,8 @@ void dboard_manager_impl::set_nice_dboard_if(void){ //set nice settings on each unit BOOST_FOREACH(dboard_iface::unit_t unit, units){ _iface->set_gpio_ddr(unit, 0x0000); //all inputs - _iface->set_atr_reg(unit, dboard_iface::ATR_REG_IDLE, 0x0000); //all low + _iface->write_gpio(unit, 0x0000); //all low + _iface->set_pin_ctrl(unit, 0x0000); //all gpio _iface->set_clock_enabled(unit, false); //clock off } } diff --git a/host/lib/usrp/usrp2/dboard_iface.cpp b/host/lib/usrp/usrp2/dboard_iface.cpp index d33a11fd6..0a2e4b550 100644 --- a/host/lib/usrp/usrp2/dboard_iface.cpp +++ b/host/lib/usrp/usrp2/dboard_iface.cpp @@ -39,8 +39,10 @@ public: void write_aux_dac(unit_t, int, float); float read_aux_adc(unit_t, int); + void set_pin_ctrl(unit_t, boost::uint16_t); void set_atr_reg(unit_t, atr_reg_t, boost::uint16_t); void set_gpio_ddr(unit_t, boost::uint16_t); + void write_gpio(unit_t, boost::uint16_t); boost::uint16_t read_gpio(unit_t); void write_i2c(boost::uint8_t, const byte_vector_t &); @@ -68,6 +70,7 @@ private: usrp2_iface::sptr _iface; clock_ctrl::sptr _clock_ctrl; boost::uint32_t _ddr_shadow; + boost::uint32_t _gpio_shadow; uhd::dict _dac_regs; void _write_aux_dac(unit_t); @@ -90,14 +93,7 @@ usrp2_dboard_iface::usrp2_dboard_iface(usrp2_iface::sptr iface, clock_ctrl::sptr _iface = iface; _clock_ctrl = clock_ctrl; _ddr_shadow = 0; - - //set the selection mux to use atr - boost::uint32_t new_sels = 0x0; - for(size_t i = 0; i < 16; i++){ - new_sels |= FRF_GPIO_SEL_ATR << (i*2); - } - _iface->poke32(FR_GPIO_TX_SEL, new_sels); - _iface->poke32(FR_GPIO_RX_SEL, new_sels); + _gpio_shadow = 0; //reset the aux dacs _dac_regs[UNIT_RX] = ad5624_regs_t(); @@ -136,6 +132,21 @@ static const uhd::dict unit_to_shift = map_list_of (dboard_iface::UNIT_TX, 16) ; +void usrp2_dboard_iface::set_pin_ctrl(unit_t unit, boost::uint16_t value){ + //calculate the new selection mux setting + boost::uint32_t new_sels = 0x0; + for(size_t i = 0; i < 16; i++){ + bool is_bit_set = bool(value & (0x1 << i)); + new_sels |= ((is_bit_set)? FRF_GPIO_SEL_ATR : FRF_GPIO_SEL_GPIO) << (i*2); + } + + //write the selection mux value to register + switch(unit){ + case UNIT_RX: _iface->poke32(FR_GPIO_RX_SEL, new_sels); return; + case UNIT_TX: _iface->poke32(FR_GPIO_TX_SEL, new_sels); return; + } +} + void usrp2_dboard_iface::set_gpio_ddr(unit_t unit, boost::uint16_t value){ _ddr_shadow = \ (_ddr_shadow & ~(0xffff << unit_to_shift[unit])) | @@ -143,6 +154,13 @@ void usrp2_dboard_iface::set_gpio_ddr(unit_t unit, boost::uint16_t value){ _iface->poke32(FR_GPIO_DDR, _ddr_shadow); } +void usrp2_dboard_iface::write_gpio(unit_t unit, boost::uint16_t value){ + _gpio_shadow = \ + (_gpio_shadow & ~(0xffff << unit_to_shift[unit])) | + (boost::uint32_t(value) << unit_to_shift[unit]); + _iface->poke32(FR_GPIO_IO, _gpio_shadow); +} + boost::uint16_t usrp2_dboard_iface::read_gpio(unit_t unit){ return boost::uint16_t(_iface->peek32(FR_GPIO_IO) >> unit_to_shift[unit]); } diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp index 0f8a739f2..0ac39d2a3 100644 --- a/host/lib/usrp/usrp2/dboard_impl.cpp +++ b/host/lib/usrp/usrp2/dboard_impl.cpp @@ -38,9 +38,7 @@ void usrp2_impl::dboard_init(void){ _tx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(I2C_ADDR_TX_DB, 0, dboard_eeprom_t::num_bytes())); //create a new dboard interface and manager - dboard_iface::sptr _dboard_iface( - make_usrp2_dboard_iface(_iface, _clock_ctrl) - ); + _dboard_iface = make_usrp2_dboard_iface(_iface, _clock_ctrl); _dboard_manager = dboard_manager::make( _rx_db_eeprom.id, _tx_db_eeprom.id, _dboard_iface ); @@ -123,6 +121,10 @@ void usrp2_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){ val = _rx_db_eeprom.id; return; + case DBOARD_PROP_DBOARD_IFACE: + val = _dboard_iface; + return; + default: UHD_THROW_PROP_GET_ERROR(); } } @@ -172,6 +174,10 @@ void usrp2_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){ val = _tx_db_eeprom.id; return; + case DBOARD_PROP_DBOARD_IFACE: + val = _dboard_iface; + return; + default: UHD_THROW_PROP_GET_ERROR(); } } diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index afea9683c..7948a2069 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -169,6 +169,7 @@ private: //rx and tx dboard methods and objects uhd::usrp::dboard_manager::sptr _dboard_manager; + uhd::usrp::dboard_iface::sptr _dboard_iface; void dboard_init(void); //properties for the mboard diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp index feeccaa34..0f675357b 100644 --- a/host/lib/usrp/usrp2/usrp2_regs.hpp +++ b/host/lib/usrp/usrp2/usrp2_regs.hpp @@ -204,7 +204,7 @@ #define FR_GPIO_RX_SEL FR_GPIO_BASE + 12 // 16 2-bit fields select which source goes to RX DB // each 2-bit sel field is layed out this way -#define FRF_GPIO_SEL_SW 0 // if pin is an output, set by software in the io reg +#define FRF_GPIO_SEL_GPIO 0 // if pin is an output, set by GPIO register #define FRF_GPIO_SEL_ATR 1 // if pin is an output, set by ATR logic #define FRF_GPIO_SEL_DEBUG_0 2 // if pin is an output, debug lines from FPGA fabric #define FRF_GPIO_SEL_DEBUG_1 3 // if pin is an output, debug lines from FPGA fabric -- cgit v1.2.3 From 4eff47a4b66eff61feffe6498b9ecebef94dc6b9 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 27 May 2010 14:10:50 -0700 Subject: Tweak with the udp and zero-copy transport. Eventually, the caller will hang onto a ring of managed buffers. --- host/include/uhd/transport/zero_copy.hpp | 5 ++-- host/lib/transport/udp_zero_copy_asio.cpp | 38 ++++++++++++++++--------------- host/lib/transport/vrt_packet_handler.hpp | 2 +- host/lib/usrp/usrp2/io_impl.cpp | 2 +- 4 files changed, 25 insertions(+), 22 deletions(-) (limited to 'host/lib') diff --git a/host/include/uhd/transport/zero_copy.hpp b/host/include/uhd/transport/zero_copy.hpp index fdc5b141c..52c6d4143 100644 --- a/host/include/uhd/transport/zero_copy.hpp +++ b/host/include/uhd/transport/zero_copy.hpp @@ -35,11 +35,12 @@ public: typedef boost::shared_ptr sptr; /*! + * Managed recv buffer destructor: * Signal to the transport that we are done with the buffer. * This should be called to release the buffer to the transport. * After calling, the referenced memory should be considered invalid. */ - virtual void done(void) = 0; + virtual ~managed_recv_buffer(void){}; /*! * Get the size of the underlying buffer. @@ -81,7 +82,7 @@ public: * After calling, the referenced memory should be considered invalid. * \param num_bytes the number of bytes written into the buffer */ - virtual void done(size_t num_bytes) = 0; + virtual void commit(size_t num_bytes) = 0; /*! * Get the size of the underlying buffer. diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index 56ba391d3..f8a222475 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -24,6 +24,13 @@ using namespace uhd::transport; +/*********************************************************************** + * Constants + **********************************************************************/ +static const size_t MIN_SOCK_BUFF_SIZE = size_t(100e3); +static const size_t MAX_DGRAM_SIZE = 2048; //assume max size on send and recv +static const double RECV_TIMEOUT = 0.1; // 100 ms + /*********************************************************************** * Managed receive buffer implementation for udp zero-copy asio: **********************************************************************/ @@ -34,11 +41,7 @@ public: } ~managed_recv_buffer_impl(void){ - /* NOP */ - } - - void done(void){ - /* NOP */ + delete [] this->cast(); } private: @@ -65,7 +68,7 @@ public: /* NOP */ } - void done(size_t num_bytes){ + void commit(size_t num_bytes){ _socket->send(boost::asio::buffer(_buff, num_bytes)); } @@ -85,8 +88,6 @@ private: * However, it is not a true zero copy implementation as each * send and recv requires a copy operation to/from userspace. **********************************************************************/ -static const size_t max_buff_size = 2000; //assume max size on send and recv - class udp_zero_copy_impl : public udp_zero_copy{ public: typedef boost::shared_ptr sptr; @@ -117,7 +118,7 @@ private: boost::asio::io_service _io_service; //send and recv buffer memory (allocated once) - boost::uint8_t _send_mem[max_buff_size], _recv_mem[max_buff_size]; + boost::uint8_t _send_mem[MIN_SOCK_BUFF_SIZE]; managed_send_buffer::sptr _send_buff; }; @@ -137,13 +138,13 @@ udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::strin // create the managed send buff (just once) _send_buff = managed_send_buffer::sptr(new managed_send_buffer_impl( - boost::asio::buffer(_send_mem, max_buff_size), _socket + boost::asio::buffer(_send_mem, MIN_SOCK_BUFF_SIZE), _socket )); // set recv timeout timeval tv; tv.tv_sec = 0; - tv.tv_usec = 100*1000; //100 ms + tv.tv_usec = size_t(RECV_TIMEOUT*1e6); UHD_ASSERT_THROW(setsockopt( _socket->native(), SOL_SOCKET, SO_RCVTIMEO, @@ -156,17 +157,20 @@ udp_zero_copy_impl::~udp_zero_copy_impl(void){ } managed_recv_buffer::sptr udp_zero_copy_impl::get_recv_buff(void){ + //allocate memory + boost::uint8_t *recv_mem = new boost::uint8_t[MAX_DGRAM_SIZE]; + //call recv() with timeout option - size_t num_bytes = _socket->receive(boost::asio::buffer(_recv_mem, max_buff_size)); + size_t num_bytes = _socket->receive(boost::asio::buffer(recv_mem, MIN_SOCK_BUFF_SIZE)); //create a new managed buffer to house the data return managed_recv_buffer::sptr( - new managed_recv_buffer_impl(boost::asio::buffer(_recv_mem, num_bytes)) + new managed_recv_buffer_impl(boost::asio::buffer(recv_mem, num_bytes)) ); } managed_send_buffer::sptr udp_zero_copy_impl::get_send_buff(void){ - return _send_buff; + return _send_buff; //FIXME there is only ever one send buff, we assume that the caller doesnt hang onto these } /*********************************************************************** @@ -177,8 +181,6 @@ template static inline void resize_buff_helper( size_t target_size, const std::string &name ){ - static const size_t min_buff_size = size_t(100e3); - //resize the buffer if size was provided if (target_size > 0){ size_t actual_size = udp_trans->resize_buff(target_size); @@ -189,8 +191,8 @@ template static inline void resize_buff_helper( } //otherwise, ensure that the buffer is at least the minimum size - else if (udp_trans->get_buff_size() < min_buff_size){ - resize_buff_helper(udp_trans, min_buff_size, name); + else if (udp_trans->get_buff_size() < MIN_SOCK_BUFF_SIZE){ + resize_buff_helper(udp_trans, MIN_SOCK_BUFF_SIZE, name); } } diff --git a/host/lib/transport/vrt_packet_handler.hpp b/host/lib/transport/vrt_packet_handler.hpp index 81420b39e..e64e3383d 100644 --- a/host/lib/transport/vrt_packet_handler.hpp +++ b/host/lib/transport/vrt_packet_handler.hpp @@ -284,7 +284,7 @@ namespace vrt_packet_handler{ send_cb(send_buff); //callback after memory filled //commit the samples to the zero-copy interface - send_buff->done(num_packet_words32*sizeof(boost::uint32_t)); + send_buff->commit(num_packet_words32*sizeof(boost::uint32_t)); } /******************************************************************* diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index b6ab919e7..79b18fb63 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -45,7 +45,7 @@ void usrp2_impl::io_init(void){ managed_send_buffer::sptr send_buff = _data_transport->get_send_buff(); boost::uint32_t data = htonl(USRP2_INVALID_VRT_HEADER); memcpy(send_buff->cast(), &data, sizeof(data)); - send_buff->done(sizeof(data)); + send_buff->commit(sizeof(data)); //setup RX DSP regs std::cout << "RX samples per packet: " << get_max_recv_samps_per_packet() << std::endl; -- cgit v1.2.3