diff options
author | Josh Blum <josh@joshknows.com> | 2010-07-07 02:23:38 +0000 |
---|---|---|
committer | Josh Blum <josh@joshknows.com> | 2010-07-07 02:23:38 +0000 |
commit | f2e9d3ed0941dc5738149dd82d1eac158bdf0a0f (patch) | |
tree | 82a350987e32cd329ab5fe56b6dd9fbfef08230f /host/lib/usrp/usrp2 | |
parent | 998fee6ef064f1d53a61dd0eec79276d1e85291e (diff) | |
parent | 5c2cccfe8c4a9c6c912a4d18dc1e7a6f84c79609 (diff) | |
download | uhd-f2e9d3ed0941dc5738149dd82d1eac158bdf0a0f.tar.gz uhd-f2e9d3ed0941dc5738149dd82d1eac158bdf0a0f.tar.bz2 uhd-f2e9d3ed0941dc5738149dd82d1eac158bdf0a0f.zip |
Merge branch 'master' of ettus.sourcerepo.com:ettus/uhdpriv into usrp_e
Conflicts:
host/examples/rx_timed_samples.cpp
Diffstat (limited to 'host/lib/usrp/usrp2')
-rw-r--r-- | host/lib/usrp/usrp2/dboard_impl.cpp | 18 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/dsp_impl.cpp | 20 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/fw_common.h | 6 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/io_impl.cpp | 195 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/mboard_impl.cpp | 100 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/usrp2_iface.cpp | 26 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/usrp2_iface.hpp | 10 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/usrp2_impl.cpp | 123 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/usrp2_impl.hpp | 198 | ||||
-rw-r--r-- | host/lib/usrp/usrp2/usrp2_regs.hpp | 10 |
10 files changed, 435 insertions, 271 deletions
diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp index fef486771..fa8d1a674 100644 --- a/host/lib/usrp/usrp2/dboard_impl.cpp +++ b/host/lib/usrp/usrp2/dboard_impl.cpp @@ -33,7 +33,7 @@ using namespace uhd::usrp; /*********************************************************************** * Helper Methods **********************************************************************/ -void usrp2_impl::dboard_init(void){ +void usrp2_mboard_impl::dboard_init(void){ //read the dboard eeprom to extract the dboard ids _rx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(I2C_ADDR_RX_DB, 0, dboard_eeprom_t::num_bytes())); _tx_db_eeprom = dboard_eeprom_t(_iface->read_eeprom(I2C_ADDR_TX_DB, 0, dboard_eeprom_t::num_bytes())); @@ -46,12 +46,12 @@ void usrp2_impl::dboard_init(void){ //load dboards _rx_dboard_proxy = wax_obj_proxy::make( - boost::bind(&usrp2_impl::rx_dboard_get, this, _1, _2), - boost::bind(&usrp2_impl::rx_dboard_set, this, _1, _2) + boost::bind(&usrp2_mboard_impl::rx_dboard_get, this, _1, _2), + boost::bind(&usrp2_mboard_impl::rx_dboard_set, this, _1, _2) ); _tx_dboard_proxy = wax_obj_proxy::make( - boost::bind(&usrp2_impl::tx_dboard_get, this, _1, _2), - boost::bind(&usrp2_impl::tx_dboard_set, this, _1, _2) + boost::bind(&usrp2_mboard_impl::tx_dboard_get, this, _1, _2), + boost::bind(&usrp2_mboard_impl::tx_dboard_set, this, _1, _2) ); //init the subdevs in use (use the first subdevice) @@ -62,7 +62,7 @@ void usrp2_impl::dboard_init(void){ /*********************************************************************** * RX DBoard Properties **********************************************************************/ -void usrp2_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){ +void usrp2_mboard_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){ wax::obj key; std::string name; boost::tie(key, name) = extract_named_prop(key_); @@ -96,7 +96,7 @@ void usrp2_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){ } } -void usrp2_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){ +void usrp2_mboard_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){ switch(key.as<dboard_prop_t>()){ case DBOARD_PROP_USED_SUBDEVS:{ _rx_subdevs_in_use = val.as<prop_names_t>(); @@ -122,7 +122,7 @@ void usrp2_impl::rx_dboard_set(const wax::obj &key, const wax::obj &val){ /*********************************************************************** * TX DBoard Properties **********************************************************************/ -void usrp2_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){ +void usrp2_mboard_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){ wax::obj key; std::string name; boost::tie(key, name) = extract_named_prop(key_); @@ -156,7 +156,7 @@ void usrp2_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){ } } -void usrp2_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val){ +void usrp2_mboard_impl::tx_dboard_set(const wax::obj &key, const wax::obj &val){ switch(key.as<dboard_prop_t>()){ case DBOARD_PROP_USED_SUBDEVS:{ _tx_subdevs_in_use = val.as<prop_names_t>(); diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index 367cde2e1..c315a2eec 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -41,11 +41,11 @@ pick_closest_rate(double exact_rate, const std::vector<rate_t> &rates){ return closest_match; } -void usrp2_impl::init_ddc_config(void){ +void usrp2_mboard_impl::init_ddc_config(void){ //create the ddc in the rx dsp dict _rx_dsp_proxy = wax_obj_proxy::make( - boost::bind(&usrp2_impl::ddc_get, this, _1, _2), - boost::bind(&usrp2_impl::ddc_set, this, _1, _2) + boost::bind(&usrp2_mboard_impl::ddc_get, this, _1, _2), + boost::bind(&usrp2_mboard_impl::ddc_set, this, _1, _2) ); //initial config and update @@ -56,7 +56,7 @@ void usrp2_impl::init_ddc_config(void){ /*********************************************************************** * DDC Properties **********************************************************************/ -void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){ +void usrp2_mboard_impl::ddc_get(const wax::obj &key, wax::obj &val){ switch(key.as<dsp_prop_t>()){ case DSP_PROP_NAME: val = std::string("usrp2 ddc0"); @@ -82,7 +82,7 @@ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){ } } -void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){ +void usrp2_mboard_impl::ddc_set(const wax::obj &key, const wax::obj &val){ switch(key.as<dsp_prop_t>()){ case DSP_PROP_FREQ_SHIFT:{ @@ -116,11 +116,11 @@ void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){ /*********************************************************************** * DUC Helper Methods **********************************************************************/ -void usrp2_impl::init_duc_config(void){ +void usrp2_mboard_impl::init_duc_config(void){ //create the duc in the tx dsp dict _tx_dsp_proxy = wax_obj_proxy::make( - boost::bind(&usrp2_impl::duc_get, this, _1, _2), - boost::bind(&usrp2_impl::duc_set, this, _1, _2) + boost::bind(&usrp2_mboard_impl::duc_get, this, _1, _2), + boost::bind(&usrp2_mboard_impl::duc_set, this, _1, _2) ); //initial config and update @@ -131,7 +131,7 @@ void usrp2_impl::init_duc_config(void){ /*********************************************************************** * DUC Properties **********************************************************************/ -void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){ +void usrp2_mboard_impl::duc_get(const wax::obj &key, wax::obj &val){ switch(key.as<dsp_prop_t>()){ case DSP_PROP_NAME: val = std::string("usrp2 duc0"); @@ -157,7 +157,7 @@ void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){ } } -void usrp2_impl::duc_set(const wax::obj &key, const wax::obj &val){ +void usrp2_mboard_impl::duc_set(const wax::obj &key, const wax::obj &val){ switch(key.as<dsp_prop_t>()){ case DSP_PROP_FREQ_SHIFT:{ diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index 242d268ec..4c66aa41e 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -38,7 +38,7 @@ extern "C" { //defines the protocol version in this shared header //increment this value when the protocol is changed -#define USRP2_PROTO_VERSION 4 +#define USRP2_PROTO_VERSION 5 //used to differentiate control packets over data port #define USRP2_INVALID_VRT_HEADER 0 @@ -111,7 +111,9 @@ typedef struct{ struct { _SINS_ uint32_t addr; _SINS_ uint32_t data; - _SINS_ uint8_t num_bytes; //1, 2, 4 + _SINS_ uint32_t addrhi; + _SINS_ uint32_t datahi; + _SINS_ uint8_t num_bytes; //1, 2, 4, 8 } poke_args; } data; } usrp2_ctrl_data_t; diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index aa0f63321..c96528694 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -20,7 +20,7 @@ #include "usrp2_regs.hpp" #include <uhd/utils/thread_priority.hpp> #include <uhd/transport/convert_types.hpp> -#include <uhd/transport/bounded_buffer.hpp> +#include <uhd/transport/alignment_buffer.hpp> #include <boost/format.hpp> #include <boost/asio.hpp> //htonl and ntohl #include <boost/bind.hpp> @@ -34,56 +34,81 @@ namespace asio = boost::asio; /*********************************************************************** * io impl details (internal to this file) + * - pirate crew + * - alignment buffer + * - thread loop + * - vrt packet handler states **********************************************************************/ struct usrp2_impl::io_impl{ + typedef alignment_buffer<managed_recv_buffer::sptr, time_spec_t> alignment_buffer_type; - io_impl(zero_copy_if::sptr zc_if); - ~io_impl(void); + io_impl(size_t num_frames, size_t width): + packet_handler_recv_state(width), + recv_pirate_booty(alignment_buffer_type::make(num_frames, width)) + { + /* NOP */ + } + + ~io_impl(void){ + recv_pirate_crew_raiding = false; + recv_pirate_crew.interrupt_all(); + recv_pirate_crew.join_all(); + } - managed_recv_buffer::sptr get_recv_buff(void); + bool get_recv_buffs(vrt_packet_handler::managed_recv_buffs_t &buffs){ + boost::this_thread::disable_interruption di; //disable because the wait can throw + return recv_pirate_booty->pop_elems_with_timed_wait(buffs, boost::posix_time::milliseconds(100)); + } //state management for the vrt packet handler code vrt_packet_handler::recv_state packet_handler_recv_state; vrt_packet_handler::send_state packet_handler_send_state; - //methods and variables for the recv pirate - void recv_pirate_loop(zero_copy_if::sptr zc_if); - boost::thread *recv_pirate_thread; bool recv_pirate_running; - bounded_buffer<managed_recv_buffer::sptr>::sptr recv_pirate_booty; + //methods and variables for the pirate crew + void recv_pirate_loop(zero_copy_if::sptr, usrp2_mboard_impl::sptr, size_t); + boost::thread_group recv_pirate_crew; + bool recv_pirate_crew_raiding; + alignment_buffer_type::sptr recv_pirate_booty; }; -usrp2_impl::io_impl::io_impl(zero_copy_if::sptr zc_if){ - //create a large enough booty - size_t num_frames = zc_if->get_num_recv_frames(); - std::cout << "Recv pirate num frames: " << num_frames << std::endl; - recv_pirate_booty = bounded_buffer<managed_recv_buffer::sptr>::make(num_frames); - - //create a new pirate thread (yarr!!) - recv_pirate_thread = new boost::thread( - boost::bind(&usrp2_impl::io_impl::recv_pirate_loop, this, zc_if) - ); -} - -usrp2_impl::io_impl::~io_impl(void){ - recv_pirate_running = false; - recv_pirate_thread->interrupt(); - recv_pirate_thread->join(); - delete recv_pirate_thread; -} - -managed_recv_buffer::sptr usrp2_impl::io_impl::get_recv_buff(void){ - managed_recv_buffer::sptr buff; - boost::this_thread::disable_interruption di; //disable because the wait can throw - recv_pirate_booty->pop_with_timed_wait(buff, boost::posix_time::milliseconds(100)); - return buff; //a timeout means that we return a null sptr... -} - -void usrp2_impl::io_impl::recv_pirate_loop(zero_copy_if::sptr zc_if){ +/*********************************************************************** + * Receive Pirate Loop + * - while raiding, loot for recv buffers + * - put booty into the alignment buffer + **********************************************************************/ +void usrp2_impl::io_impl::recv_pirate_loop( + zero_copy_if::sptr zc_if, + usrp2_mboard_impl::sptr mboard, + size_t index +){ set_thread_priority_safe(); - recv_pirate_running = true; - while(recv_pirate_running){ + recv_pirate_crew_raiding = true; + while(recv_pirate_crew_raiding){ managed_recv_buffer::sptr buff = zc_if->get_recv_buff(); - if (buff->size()) recv_pirate_booty->push_with_pop_on_full(buff); + if (buff->size() == 0) continue; //ignore timeout buffers + + try{ + //extract the vrt header packet info + vrt::if_packet_info_t if_packet_info; + if_packet_info.num_packet_words32 = buff->size()/sizeof(boost::uint32_t); + vrt::if_hdr_unpack_be(buff->cast<const boost::uint32_t *>(), if_packet_info); + + //extract the timespec and round to the nearest packet + UHD_ASSERT_THROW(if_packet_info.has_tsi and if_packet_info.has_tsf); + + //size_t pkt_dur_ticks = mboard->get_master_clock_freq() * 1; //TODO FIXME + //size_t(if_packet_info.tsf) - size_t(if_packet_info.tsf)%pkt_dur_ticks + //the idea is to round the time specs to packet boundaries to avoid the issue + //of never getting alignment when things are not locked properly + time_spec_t time( + time_t(if_packet_info.tsi), size_t(if_packet_info.tsf), mboard->get_master_clock_freq() + ); + + //push the packet into the buffer with the new time + recv_pirate_booty->push_with_pop_on_full(buff, time, index); + }catch(const std::exception &e){ + std::cerr << "Error (usrp2 recv pirate loop): " << e.what() << std::endl; + } } } @@ -91,58 +116,64 @@ void usrp2_impl::io_impl::recv_pirate_loop(zero_copy_if::sptr zc_if){ * Helper Functions **********************************************************************/ void usrp2_impl::io_init(void){ - //setup rx otw type - _rx_otw_type.width = 16; - _rx_otw_type.shift = 0; - _rx_otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN; + //send a small data packet so the usrp2 knows the udp source port + for(size_t i = 0; i < _data_transports.size(); i++){ + managed_send_buffer::sptr send_buff = _data_transports[i]->get_send_buff(); + boost::uint32_t data = htonl(USRP2_INVALID_VRT_HEADER); + memcpy(send_buff->cast<void*>(), &data, sizeof(data)); + send_buff->commit(sizeof(data)); + } - //setup tx otw type - _tx_otw_type.width = 16; - _tx_otw_type.shift = 0; - _tx_otw_type.byteorder = otw_type_t::BO_BIG_ENDIAN; + //the number of recv frames is the number for the first transport + //the assumption is that all data transports should be identical + size_t num_frames = _data_transports.front()->get_num_recv_frames(); - //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); - memcpy(send_buff->cast<void*>(), &data, sizeof(data)); - send_buff->commit(sizeof(data)); + //create new io impl + _io_impl = UHD_PIMPL_MAKE(io_impl, (num_frames, _data_transports.size())); + + //create a new pirate thread for each zc if (yarr!!) + for (size_t i = 0; i < _data_transports.size(); i++){ + _io_impl->recv_pirate_crew.create_thread(boost::bind( + &usrp2_impl::io_impl::recv_pirate_loop, + _io_impl, _data_transports.at(i), + _mboards.at(i), i + )); + } - //setup RX DSP regs std::cout << "RX samples per packet: " << get_max_recv_samps_per_packet() << std::endl; - _iface->poke32(U2_REG_RX_CTRL_NSAMPS_PER_PKT, get_max_recv_samps_per_packet()); - _iface->poke32(U2_REG_RX_CTRL_NCHANNELS, 1); - _iface->poke32(U2_REG_RX_CTRL_CLEAR_OVERRUN, 1); //reset - _iface->poke32(U2_REG_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(U2_REG_RX_CTRL_VRT_STREAM_ID, 0); - _iface->poke32(U2_REG_RX_CTRL_VRT_TRAILER, 0); - std::cout << "TX samples per packet: " << get_max_send_samps_per_packet() << std::endl; - - //create new io impl - _io_impl = UHD_PIMPL_MAKE(io_impl, (_data_transport)); + std::cout << "Recv pirate num frames: " << num_frames << std::endl; } /*********************************************************************** * Send Data **********************************************************************/ +bool get_send_buffs( + const std::vector<udp_zero_copy::sptr> &trans, + vrt_packet_handler::managed_send_buffs_t &buffs +){ + UHD_ASSERT_THROW(trans.size() == buffs.size()); + for (size_t i = 0; i < buffs.size(); i++){ + buffs[i] = trans[i]->get_send_buff(); + } + return true; +} + size_t usrp2_impl::send( - const asio::const_buffer &buff, + const std::vector<const void *> &buffs, + size_t num_samps, const tx_metadata_t &metadata, const io_type_t &io_type, send_mode_t send_mode ){ return vrt_packet_handler::send( - _io_impl->packet_handler_send_state, //last state of the send handler - 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 - uhd::transport::vrt::pack_be, - boost::bind(&zero_copy_if::get_send_buff, _data_transport), + _io_impl->packet_handler_send_state, //last state of the send handler + buffs, num_samps, //buffer to fill + metadata, send_mode, //samples metadata + io_type, _io_helper.get_tx_otw_type(), //input and output types to convert + _mboards.front()->get_master_clock_freq(), //master clock tick rate + uhd::transport::vrt::if_hdr_pack_be, + boost::bind(&get_send_buffs, _data_transports, _1), get_max_send_samps_per_packet() ); } @@ -151,17 +182,19 @@ size_t usrp2_impl::send( * Receive Data **********************************************************************/ size_t usrp2_impl::recv( - const asio::mutable_buffer &buff, + const std::vector<void *> &buffs, + size_t num_samps, rx_metadata_t &metadata, const io_type_t &io_type, recv_mode_t recv_mode ){ return vrt_packet_handler::recv( - _io_impl->packet_handler_recv_state, //last state of the recv handler - 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 - uhd::transport::vrt::unpack_be, - boost::bind(&usrp2_impl::io_impl::get_recv_buff, _io_impl) + _io_impl->packet_handler_recv_state, //last state of the recv handler + buffs, num_samps, //buffer to fill + metadata, recv_mode, //samples metadata + io_type, _io_helper.get_rx_otw_type(), //input and output types to convert + _mboards.front()->get_master_clock_freq(), //master clock tick rate + uhd::transport::vrt::if_hdr_unpack_be, + boost::bind(&usrp2_impl::io_impl::get_recv_buffs, _io_impl, _1) ); } diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 78fc5dc23..952954286 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -25,21 +25,77 @@ #include <boost/bind.hpp> #include <boost/asio/ip/address_v4.hpp> #include <boost/assign/list_of.hpp> +#include <iostream> using namespace uhd; using namespace uhd::usrp; /*********************************************************************** - * Helper Methods + * Structors **********************************************************************/ -void usrp2_impl::mboard_init(void){ - _mboard_proxy = wax_obj_proxy::make( - boost::bind(&usrp2_impl::mboard_get, this, _1, _2), - boost::bind(&usrp2_impl::mboard_set, this, _1, _2) +usrp2_mboard_impl::usrp2_mboard_impl( + size_t index, + transport::udp_simple::sptr ctrl_transport, + const usrp2_io_helper &io_helper +): + _index(index), + _io_helper(io_helper) +{ + //make a new interface for usrp2 stuff + _iface = usrp2_iface::make(ctrl_transport); + _clock_ctrl = usrp2_clock_ctrl::make(_iface); + _codec_ctrl = usrp2_codec_ctrl::make(_iface); + _serdes_ctrl = usrp2_serdes_ctrl::make(_iface); + + //TODO move to dsp impl... + //load the allowed decim/interp rates + //_USRP2_RATES = range(4, 128+1, 1) + range(130, 256+1, 2) + range(260, 512+1, 4) + _allowed_decim_and_interp_rates.clear(); + for (size_t i = 4; i <= 128; i+=1){ + _allowed_decim_and_interp_rates.push_back(i); + } + for (size_t i = 130; i <= 256; i+=2){ + _allowed_decim_and_interp_rates.push_back(i); + } + for (size_t i = 260; i <= 512; i+=4){ + _allowed_decim_and_interp_rates.push_back(i); + } + + //setup the vrt rx registers + _iface->poke32(U2_REG_RX_CTRL_NSAMPS_PER_PKT, _io_helper.get_max_recv_samps_per_packet()); + _iface->poke32(U2_REG_RX_CTRL_NCHANNELS, 1); + _iface->poke32(U2_REG_RX_CTRL_CLEAR_OVERRUN, 1); //reset + _iface->poke32(U2_REG_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(U2_REG_RX_CTRL_VRT_STREAM_ID, 0); + _iface->poke32(U2_REG_RX_CTRL_VRT_TRAILER, 0); + _iface->poke32(U2_REG_TIME64_TPS, size_t(get_master_clock_freq())); + + //init the ddc + init_ddc_config(); + + //init the duc + init_duc_config(); + + //initialize the clock configuration + init_clock_config(); + + //init the tx and rx dboards (do last) + dboard_init(); } -void usrp2_impl::init_clock_config(void){ +usrp2_mboard_impl::~usrp2_mboard_impl(void){ + /* NOP */ +} + +/*********************************************************************** + * Helper Methods + **********************************************************************/ +void usrp2_mboard_impl::init_clock_config(void){ //setup the clock configuration settings _clock_config.ref_source = clock_config_t::REF_INT; _clock_config.pps_source = clock_config_t::PPS_SMA; @@ -49,7 +105,7 @@ void usrp2_impl::init_clock_config(void){ update_clock_config(); } -void usrp2_impl::update_clock_config(void){ +void usrp2_mboard_impl::update_clock_config(void){ boost::uint32_t pps_flags = 0; //translate pps source enums @@ -82,19 +138,19 @@ void usrp2_impl::update_clock_config(void){ _clock_ctrl->enable_external_ref(use_external); } -void usrp2_impl::set_time_spec(const time_spec_t &time_spec, bool now){ +void usrp2_mboard_impl::set_time_spec(const time_spec_t &time_spec, bool now){ //set the ticks - _iface->poke32(U2_REG_TIME64_TICKS, time_spec.get_ticks(get_master_clock_freq())); + _iface->poke32(U2_REG_TIME64_TICKS, time_spec.get_tick_count(get_master_clock_freq())); //set the flags register boost::uint32_t imm_flags = (now)? U2_FLAG_TIME64_LATCH_NOW : U2_FLAG_TIME64_LATCH_NEXT_PPS; _iface->poke32(U2_REG_TIME64_IMM, imm_flags); //set the seconds (latches in all 3 registers) - _iface->poke32(U2_REG_TIME64_SECS, time_spec.secs); + _iface->poke32(U2_REG_TIME64_SECS, boost::uint32_t(time_spec.get_full_secs())); } -void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ +void usrp2_mboard_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ UHD_ASSERT_THROW(stream_cmd.num_samps <= U2_REG_RX_CTRL_MAX_SAMPS_PER_CMD); //setup the mode to instruction flags @@ -113,19 +169,19 @@ void usrp2_impl::issue_ddc_stream_cmd(const stream_cmd_t &stream_cmd){ //issue the stream command _iface->poke32(U2_REG_RX_CTRL_STREAM_CMD, U2_REG_RX_CTRL_MAKE_CMD( - (inst_samps)? stream_cmd.num_samps : ((inst_chain)? get_max_recv_samps_per_packet() : 1), + (inst_samps)? stream_cmd.num_samps : ((inst_chain)? _io_helper.get_max_recv_samps_per_packet() : 1), (stream_cmd.stream_now)? 1 : 0, (inst_chain)? 1 : 0, (inst_reload)? 1 : 0 )); - _iface->poke32(U2_REG_RX_CTRL_TIME_SECS, stream_cmd.time_spec.secs); - _iface->poke32(U2_REG_RX_CTRL_TIME_TICKS, stream_cmd.time_spec.get_ticks(get_master_clock_freq())); + _iface->poke32(U2_REG_RX_CTRL_TIME_SECS, boost::uint32_t(stream_cmd.time_spec.get_full_secs())); + _iface->poke32(U2_REG_RX_CTRL_TIME_TICKS, stream_cmd.time_spec.get_tick_count(get_master_clock_freq())); } /*********************************************************************** * MBoard Get Properties **********************************************************************/ -void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ +void usrp2_mboard_impl::get(const wax::obj &key_, wax::obj &val){ wax::obj key; std::string name; boost::tie(key, name) = extract_named_prop(key_); @@ -148,7 +204,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ //handle the get request conditioned on the key switch(key.as<mboard_prop_t>()){ case MBOARD_PROP_NAME: - val = std::string("usrp2 mboard"); + val = str(boost::format("usrp2 mboard %d") % _index); return; case MBOARD_PROP_OTHERS:{ @@ -200,6 +256,16 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ val = _clock_config; return; + case MBOARD_PROP_TIME_NOW:{ + usrp2_iface::pair64 time64( + _iface->peek64(U2_REG_TIME64_SECS_RB, U2_REG_TIME64_TICKS_RB) + ); + val = time_spec_t( + time64.first, time64.second, get_master_clock_freq() + ); + } + return; + default: UHD_THROW_PROP_GET_ERROR(); } } @@ -207,7 +273,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ /*********************************************************************** * MBoard Set Properties **********************************************************************/ -void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){ +void usrp2_mboard_impl::set(const wax::obj &key, const wax::obj &val){ //handle the other props if (key.type() == typeid(std::string)){ if (key.as<std::string>() == "mac-addr"){ diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp index 83e98904e..faf4a5c7e 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.cpp +++ b/host/lib/usrp/usrp2/usrp2_iface.cpp @@ -59,6 +59,20 @@ public: return this->peek<boost::uint16_t>(addr); } + pair64 peek64(boost::uint32_t addrlo, boost::uint32_t addrhi){ + //setup the out data + usrp2_ctrl_data_t out_data; + out_data.id = htonl(USRP2_CTRL_ID_PEEK_AT_THIS_REGISTER_FOR_ME_BRO); + out_data.data.poke_args.addr = htonl(addrlo); + out_data.data.poke_args.addrhi = htonl(addrhi); + out_data.data.poke_args.num_bytes = sizeof(boost::uint64_t); + + //send and recv + usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data); + UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE); + return pair64(ntohl(in_data.data.poke_args.data), ntohl(in_data.data.poke_args.datahi)); + } + /*********************************************************************** * SPI **********************************************************************/ @@ -86,7 +100,7 @@ public: //send and recv usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data); - UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE); + UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE); return ntohl(in_data.data.spi_args.data); } @@ -109,7 +123,7 @@ public: //send and recv usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data); - UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE); + UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE); } byte_vector_t read_i2c(boost::uint8_t addr, size_t num_bytes){ @@ -124,7 +138,7 @@ public: //send and recv usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data); - UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE); + UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE); UHD_ASSERT_THROW(in_data.data.i2c_args.addr = num_bytes); //copy out the data @@ -187,7 +201,7 @@ private: //send and recv usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data); - UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_OMG_POKED_REGISTER_SO_BAD_DUDE); + UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_OMG_POKED_REGISTER_SO_BAD_DUDE); } template <class T> T peek(boost::uint32_t addr){ @@ -199,8 +213,8 @@ private: //send and recv usrp2_ctrl_data_t in_data = this->ctrl_send_and_recv(out_data); - UHD_ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE); - return T(ntohl(out_data.data.poke_args.data)); + UHD_ASSERT_THROW(ntohl(in_data.id) == USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE); + return T(ntohl(in_data.data.poke_args.data)); } }; diff --git a/host/lib/usrp/usrp2/usrp2_iface.hpp b/host/lib/usrp/usrp2/usrp2_iface.hpp index 7b2a3a89d..9cc32104e 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.hpp +++ b/host/lib/usrp/usrp2/usrp2_iface.hpp @@ -23,6 +23,7 @@ #include <boost/shared_ptr.hpp> #include <boost/utility.hpp> #include <boost/cstdint.hpp> +#include <utility> #include "fw_common.h" //////////////////////////////////////////////////////////////////////// @@ -49,6 +50,7 @@ class usrp2_iface : public uhd::i2c_iface, boost::noncopyable{ public: typedef boost::shared_ptr<usrp2_iface> sptr; + typedef std::pair<boost::uint32_t, boost::uint32_t> pair64; /*! * Make a new usrp2 interface with the control transport. @@ -65,6 +67,14 @@ public: virtual usrp2_ctrl_data_t ctrl_send_and_recv(const usrp2_ctrl_data_t &data) = 0; /*! + * Read a dual register (64 bits) + * \param addrlo the address for the low-32 bits + * \param addrhi the address for the high-32 bits + * \return a pair of 32 bit integers lo, hi + */ + virtual pair64 peek64(boost::uint32_t addrlo, boost::uint32_t addrhi) = 0; + + /*! * Write a register (32 bits) * \param addr the address * \param data the 32bit data diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 36c264c3c..3402c26b1 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -21,6 +21,7 @@ #include <uhd/usrp/device_props.hpp> #include <uhd/utils/assert.hpp> #include <uhd/utils/static.hpp> +#include <boost/algorithm/string.hpp> #include <boost/assign/list_of.hpp> #include <boost/format.hpp> #include <boost/foreach.hpp> @@ -34,14 +35,23 @@ using namespace uhd::usrp; using namespace uhd::transport; namespace asio = boost::asio; -UHD_STATIC_BLOCK(register_usrp2_device){ - device::register_device(&usrp2::find, &usrp2::make); +/*********************************************************************** + * Helper Functions + **********************************************************************/ +std::vector<std::string> split_addrs(const std::string &addrs_str){ + std::vector<std::string> addrs; + boost::split(addrs, addrs_str, boost::is_any_of("\t ")); + return addrs; +} + +template <class T> std::string num2str(T num){ + return boost::lexical_cast<std::string>(num); } /*********************************************************************** * Discovery over the udp transport **********************************************************************/ -uhd::device_addrs_t usrp2::find(const device_addr_t &hint){ +static uhd::device_addrs_t usrp2_find(const device_addr_t &hint){ device_addrs_t usrp2_addrs; //return an empty list of addresses when type is set to non-usrp2 @@ -58,7 +68,7 @@ uhd::device_addrs_t usrp2::find(const device_addr_t &hint){ new_hint["addr"] = if_addrs.bcast; //call discover with the new hint and append results - device_addrs_t new_usrp2_addrs = usrp2::find(new_hint); + device_addrs_t new_usrp2_addrs = usrp2_find(new_hint); usrp2_addrs.insert(usrp2_addrs.begin(), new_usrp2_addrs.begin(), new_usrp2_addrs.end() ); @@ -66,6 +76,16 @@ uhd::device_addrs_t usrp2::find(const device_addr_t &hint){ return usrp2_addrs; } + //if there are multiple addresses, just return good, dont test + std::vector<std::string> addrs = split_addrs(hint["addr"]); + if (addrs.size() > 1){ + device_addr_t new_addr; + new_addr["type"] = "usrp2"; + new_addr["addr"] = hint["addr"]; + usrp2_addrs.push_back(new_addr); + return usrp2_addrs; + } + //create a udp transport to communicate std::string ctrl_port = boost::lexical_cast<std::string>(USRP2_UDP_CTRL_PORT); udp_simple::sptr udp_transport = udp_simple::make_broadcast( @@ -107,16 +127,7 @@ uhd::device_addrs_t usrp2::find(const device_addr_t &hint){ /*********************************************************************** * Make **********************************************************************/ -template <class T> std::string num2str(T num){ - return boost::lexical_cast<std::string>(num); -} - -device::sptr usrp2::make(const device_addr_t &device_addr){ - //create a control transport - udp_simple::sptr ctrl_transport = udp_simple::make_connected( - device_addr["addr"], num2str(USRP2_UDP_CTRL_PORT) - ); - +static device::sptr usrp2_make(const device_addr_t &device_addr){ //extract the receive and send buffer sizes size_t recv_buff_size = 0, send_buff_size= 0 ; if (device_addr.has_key("recv_buff_size")){ @@ -126,62 +137,48 @@ device::sptr usrp2::make(const device_addr_t &device_addr){ send_buff_size = size_t(boost::lexical_cast<double>(device_addr["send_buff_size"])); } - //create a data transport - udp_zero_copy::sptr data_transport = udp_zero_copy::make( - device_addr["addr"], - num2str(USRP2_UDP_DATA_PORT), - recv_buff_size, - send_buff_size - ); + //create a ctrl and data transport for each address + std::vector<udp_simple::sptr> ctrl_transports; + std::vector<udp_zero_copy::sptr> data_transports; + + BOOST_FOREACH(const std::string &addr, split_addrs(device_addr["addr"])){ + ctrl_transports.push_back(udp_simple::make_connected( + addr, num2str(USRP2_UDP_CTRL_PORT) + )); + data_transports.push_back(udp_zero_copy::make( + addr, num2str(USRP2_UDP_DATA_PORT), + recv_buff_size, send_buff_size + )); + } //create the usrp2 implementation guts return device::sptr( - new usrp2_impl(ctrl_transport, data_transport) + new usrp2_impl(ctrl_transports, data_transports) ); } +UHD_STATIC_BLOCK(register_usrp2_device){ + device::register_device(&usrp2_find, &usrp2_make); +} + /*********************************************************************** * Structors **********************************************************************/ usrp2_impl::usrp2_impl( - udp_simple::sptr ctrl_transport, - udp_zero_copy::sptr data_transport -){ - _data_transport = data_transport; - - //make a new interface for usrp2 stuff - _iface = usrp2_iface::make(ctrl_transport); - _clock_ctrl = usrp2_clock_ctrl::make(_iface); - _codec_ctrl = usrp2_codec_ctrl::make(_iface); - _serdes_ctrl = usrp2_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) - _allowed_decim_and_interp_rates.clear(); - for (size_t i = 4; i <= 128; i+=1){ - _allowed_decim_and_interp_rates.push_back(i); + std::vector<udp_simple::sptr> ctrl_transports, + std::vector<udp_zero_copy::sptr> data_transports +): + _data_transports(data_transports) +{ + //create a new mboard handler for each control transport + for(size_t i = 0; i < ctrl_transports.size(); i++){ + _mboards.push_back(usrp2_mboard_impl::sptr( + new usrp2_mboard_impl(i, ctrl_transports[i], _io_helper) + )); + //use an empty name when there is only one mboard + std::string name = (ctrl_transports.size() > 1)? boost::lexical_cast<std::string>(i) : ""; + _mboard_dict[name] = _mboards.back(); } - for (size_t i = 130; i <= 256; i+=2){ - _allowed_decim_and_interp_rates.push_back(i); - } - for (size_t i = 260; i <= 512; i+=4){ - _allowed_decim_and_interp_rates.push_back(i); - } - - //init the mboard - mboard_init(); - - //init the ddc - init_ddc_config(); - - //init the duc - init_duc_config(); - - //initialize the clock configuration - init_clock_config(); - - //init the tx and rx dboards (do last) - dboard_init(); //init the send and recv io io_init(); @@ -202,16 +199,16 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){ //handle the get request conditioned on the key switch(key.as<device_prop_t>()){ case DEVICE_PROP_NAME: - val = std::string("usrp2 device"); + if (_mboards.size() > 1) val = std::string("usrp2 mimo device"); + else val = std::string("usrp2 device"); return; case DEVICE_PROP_MBOARD: - UHD_ASSERT_THROW(name == ""); - val = _mboard_proxy->get_link(); + val = _mboard_dict[name]->get_link(); return; case DEVICE_PROP_MBOARD_NAMES: - val = prop_names_t(1, ""); + val = prop_names_t(_mboard_dict.keys()); 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 2126b9565..42630a3e4 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -22,7 +22,7 @@ #include "clock_ctrl.hpp" #include "codec_ctrl.hpp" #include "serdes_ctrl.hpp" -#include <uhd/usrp/usrp2.hpp> +#include <uhd/device.hpp> #include <uhd/utils/pimpl.hpp> #include <uhd/types/dict.hpp> #include <uhd/types/otw_type.hpp> @@ -31,7 +31,7 @@ #include <uhd/usrp/dboard_eeprom.hpp> #include <boost/shared_ptr.hpp> #include <boost/function.hpp> -#include <uhd/transport/vrt.hpp> +#include <uhd/transport/vrt_if_packet.hpp> #include <uhd/transport/udp_zero_copy.hpp> #include <uhd/usrp/dboard_manager.hpp> @@ -62,73 +62,84 @@ public: return sptr(new wax_obj_proxy(get, set)); } - ~wax_obj_proxy(void){ - /* NOP */ +private: + get_t _get; set_t _set; + wax_obj_proxy(const get_t &get, const set_t &set): _get(get), _set(set){}; + void get(const wax::obj &key, wax::obj &val){return _get(key, val);} + void set(const wax::obj &key, const wax::obj &val){return _set(key, val);} +}; + +/*! + * The io helper class encapculates the max packet sizes and otw types. + * The otw types are read-only for now, this will be reimplemented + * when it becomes possible to change the otw type in the usrp2. + */ +class usrp2_io_helper{ +public: + usrp2_io_helper(void){ + //setup rx otw type + _rx_otw_type.width = 16; + _rx_otw_type.shift = 0; + _rx_otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN; + + //setup tx otw type + _tx_otw_type.width = 16; + _tx_otw_type.shift = 0; + _tx_otw_type.byteorder = uhd::otw_type_t::BO_BIG_ENDIAN; } -private: - get_t _get; - set_t _set; + inline size_t get_max_send_samps_per_packet(void) const{ + return _max_tx_bytes_per_packet/_tx_otw_type.get_sample_size(); + } - wax_obj_proxy(const get_t &get, const set_t &set){ - _get = get; - _set = set; - }; + inline size_t get_max_recv_samps_per_packet(void) const{ + return _max_rx_bytes_per_packet/_rx_otw_type.get_sample_size(); + } - void get(const wax::obj &key, wax::obj &val){ - return _get(key, val); + inline const uhd::otw_type_t &get_rx_otw_type(void) const{ + return _rx_otw_type; } - void set(const wax::obj &key, const wax::obj &val){ - return _set(key, val); + inline const uhd::otw_type_t &get_tx_otw_type(void) const{ + return _tx_otw_type; } + +private: + uhd::otw_type_t _rx_otw_type, _tx_otw_type; + static const size_t _max_rx_bytes_per_packet = + USRP2_UDP_BYTES - + 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_bytes_per_packet = + USRP2_UDP_BYTES - + uhd::transport::vrt::max_if_hdr_words32*sizeof(boost::uint32_t) - + sizeof(uhd::transport::vrt::if_packet_info_t().cid) //no class id ever used + ; }; /*! - * USRP2 implementation guts: + * USRP2 mboard implementation guts: * The implementation details are encapsulated here. * Handles properties on the mboard, dboard, dsps... */ -class usrp2_impl : public uhd::device{ +class usrp2_mboard_impl : public wax::obj{ public: - /*! - * Create a new usrp2 impl base. - * \param ctrl_transport the udp transport for control - * \param data_transport the udp transport for data - */ - usrp2_impl( - uhd::transport::udp_simple::sptr ctrl_transport, - uhd::transport::udp_zero_copy::sptr data_transport - ); + typedef boost::shared_ptr<usrp2_mboard_impl> sptr; - ~usrp2_impl(void); + //structors + usrp2_mboard_impl(size_t index, uhd::transport::udp_simple::sptr, const usrp2_io_helper &); + ~usrp2_mboard_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 &, - const uhd::io_type_t &, - uhd::device::recv_mode_t - ); - -private: inline double get_master_clock_freq(void){ return _clock_ctrl->get_master_clock_rate(); } - //device properties interface +private: + size_t _index; + const usrp2_io_helper &_io_helper; + + //properties for this mboard void get(const wax::obj &, wax::obj &); void set(const wax::obj &, const wax::obj &); @@ -138,25 +149,10 @@ private: usrp2_codec_ctrl::sptr _codec_ctrl; usrp2_serdes_ctrl::sptr _serdes_ctrl; - /******************************************************************* - * Deal with the rx and tx packet sizes - ******************************************************************/ - static const size_t _max_rx_bytes_per_packet = - USRP2_UDP_BYTES - - 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_bytes_per_packet = - USRP2_UDP_BYTES - - uhd::transport::vrt::max_header_words32*sizeof(boost::uint32_t) - ; - - uhd::otw_type_t _rx_otw_type, _tx_otw_type; - UHD_PIMPL_DECL(io_impl) _io_impl; - void io_init(void); - - //udp transports for control and data - uhd::transport::udp_zero_copy::sptr _data_transport; + //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); //methods and shadows for clock configuration uhd::clock_config_t _clock_config; @@ -164,17 +160,6 @@ private: void update_clock_config(void); void set_time_spec(const uhd::time_spec_t &time_spec, bool now); - //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 - void mboard_init(void); - void mboard_get(const wax::obj &, wax::obj &); - void mboard_set(const wax::obj &, const wax::obj &); - wax_obj_proxy::sptr _mboard_proxy; - //properties interface for rx dboard void rx_dboard_get(const wax::obj &, wax::obj &); void rx_dboard_set(const wax::obj &, const wax::obj &); @@ -213,4 +198,59 @@ private: }; +/*! + * USRP2 implementation guts: + * The implementation details are encapsulated here. + * Handles device properties and streaming... + */ +class usrp2_impl : public uhd::device{ +public: + /*! + * Create a new usrp2 impl base. + * \param ctrl_transports the udp transports for control + * \param data_transports the udp transports for data + */ + usrp2_impl( + std::vector<uhd::transport::udp_simple::sptr> ctrl_transports, + std::vector<uhd::transport::udp_zero_copy::sptr> data_transports + ); + + ~usrp2_impl(void); + + //the io interface + size_t get_max_send_samps_per_packet(void) const{ + return _io_helper.get_max_send_samps_per_packet(); + } + size_t send( + const std::vector<const void *> &, size_t, + 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 _io_helper.get_max_recv_samps_per_packet(); + } + size_t recv( + const std::vector<void *> &, size_t, + uhd::rx_metadata_t &, + const uhd::io_type_t &, + uhd::device::recv_mode_t + ); + +private: + //device properties interface + void get(const wax::obj &, wax::obj &); + void set(const wax::obj &, const wax::obj &); + + //pointers to mboards on this device (think mimo setup) + std::vector<usrp2_mboard_impl::sptr> _mboards; + uhd::dict<std::string, usrp2_mboard_impl::sptr> _mboard_dict; + + //io impl methods and members + std::vector<uhd::transport::udp_zero_copy::sptr> _data_transports; + const usrp2_io_helper _io_helper; + UHD_PIMPL_DECL(io_impl) _io_impl; + void io_init(void); +}; + #endif /* INCLUDED_USRP2_IMPL_HPP */ diff --git a/host/lib/usrp/usrp2/usrp2_regs.hpp b/host/lib/usrp/usrp2/usrp2_regs.hpp index 589fa71a3..c859d3603 100644 --- a/host/lib/usrp/usrp2/usrp2_regs.hpp +++ b/host/lib/usrp/usrp2/usrp2_regs.hpp @@ -18,8 +18,6 @@ #ifndef INCLUDED_USRP2_REGS_HPP #define INCLUDED_USRP2_REGS_HPP -#include <boost/cstdint.hpp> - //////////////////////////////////////////////////// // Settings Bus, Slave #7, Not Byte Addressable! // @@ -46,7 +44,7 @@ #define SR_SIMTIMER 198 #define SR_LAST 255 -#define _SR_ADDR(sr) (MISC_OUTPUT_BASE + (sr) * sizeof(boost::uint32_t)) +#define _SR_ADDR(sr) ((MISC_OUTPUT_BASE) + (4*(sr))) ///////////////////////////////////////////////// // SPI Slave Constants @@ -104,7 +102,11 @@ #define U2_REG_TIME64_SECS _SR_ADDR(SR_TIME64 + 0) // value to set absolute secs to on next PPS #define U2_REG_TIME64_TICKS _SR_ADDR(SR_TIME64 + 1) // value to set absolute ticks to on next PPS #define U2_REG_TIME64_FLAGS _SR_ADDR(SR_TIME64 + 2) // flags - see chart above -#define U2_REG_TIME64_IMM _SR_ADDR(SR_TIME64 + 3) // set immediate (0=latch on next pps, 1=latch immediate, default=0) +#define U2_REG_TIME64_IMM _SR_ADDR(SR_TIME64 + 3) // set immediate (0=latch on next pps, 1=latch immediate, default=0) +#define U2_REG_TIME64_TPS _SR_ADDR(SR_TIME64 + 4) // the ticks per second rollover count + +#define U2_REG_TIME64_SECS_RB (0xCC00 + 4*10) +#define U2_REG_TIME64_TICKS_RB (0xCC00 + 4*11) //pps flags (see above) #define U2_FLAG_TIME64_PPS_NEGEDGE (0 << 0) |