From a4452018d17329ca02fbda85cc6b6ac21084094a Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 26 Feb 2010 12:01:03 -0800 Subject: removed empty uhd.hpp and cpp files --- host/apps/discover_usrps.cpp | 2 +- host/include/CMakeLists.txt | 5 ----- host/include/uhd.hpp | 24 ------------------------ host/lib/CMakeLists.txt | 1 - host/lib/uhd.cpp | 20 -------------------- 5 files changed, 1 insertion(+), 51 deletions(-) delete mode 100644 host/include/uhd.hpp delete mode 100644 host/lib/uhd.cpp diff --git a/host/apps/discover_usrps.cpp b/host/apps/discover_usrps.cpp index 7e8c21673..5172a4a26 100644 --- a/host/apps/discover_usrps.cpp +++ b/host/apps/discover_usrps.cpp @@ -15,7 +15,7 @@ // along with this program. If not, see . // -#include +#include #include #include #include diff --git a/host/include/CMakeLists.txt b/host/include/CMakeLists.txt index 34b705cab..3f7ca2cb7 100644 --- a/host/include/CMakeLists.txt +++ b/host/include/CMakeLists.txt @@ -17,8 +17,3 @@ ADD_SUBDIRECTORY(uhd) - -INSTALL(FILES - uhd.hpp - DESTINATION ${HEADER_DIR} -) diff --git a/host/include/uhd.hpp b/host/include/uhd.hpp deleted file mode 100644 index ee8c13dfe..000000000 --- a/host/include/uhd.hpp +++ /dev/null @@ -1,24 +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_UHD_HPP -#define INCLUDED_UHD_HPP - -//include convenience headers -#include - -#endif /* INCLUDED_UHD_HPP */ diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index edfefa127..97f1ac52e 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -22,7 +22,6 @@ SET(libuhd_sources device.cpp device_addr.cpp gain_handler.cpp - uhd.cpp wax.cpp transport/udp.cpp usrp/dboard/basic.cpp diff --git a/host/lib/uhd.cpp b/host/lib/uhd.cpp deleted file mode 100644 index 5e250c76f..000000000 --- a/host/lib/uhd.cpp +++ /dev/null @@ -1,20 +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 - -//nothing here, just includes the header so the compiler can check -- cgit v1.2.3 From 606b896cb964c38ddfed0f0e5785237f9a4d0034 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 26 Feb 2010 18:57:03 -0800 Subject: fix for io types --- host/lib/usrp/usrp2/io_impl.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 43334ddc6..c9a7b5fa4 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -26,8 +26,8 @@ using namespace uhd::usrp; /*********************************************************************** * Constants **********************************************************************/ -typedef std::complex fc32_t; -typedef std::complex sc16_t; +typedef std::complex fc32_t; +typedef std::complex sc16_t; static const float float_scale_factor = pow(2.0, 15); @@ -159,7 +159,7 @@ size_t usrp2_impl::send( const uhd::metadata_t &metadata, const std::string &type ){ - if (type == "fc32"){ + if (type == "32fc"){ size_t num_samps = boost::asio::buffer_size(buff)/sizeof(fc32_t); boost::shared_array raw_mem(new sc16_t[num_samps]); boost::asio::mutable_buffer raw_buff(raw_mem.get(), num_samps*sizeof(sc16_t)); @@ -173,7 +173,7 @@ size_t usrp2_impl::send( return send_raw(raw_buff, metadata); } - if (type == "sc16"){ + if (type == "16sc"){ #ifdef HAVE_BIG_ENDIAN return send_raw(buff, metadata); #else @@ -202,7 +202,7 @@ size_t usrp2_impl::recv( uhd::metadata_t &metadata, const std::string &type ){ - if (type == "fc32"){ + if (type == "32fc"){ size_t num_samps = boost::asio::buffer_size(buff)/sizeof(fc32_t); boost::shared_array raw_mem(new sc16_t[num_samps]); boost::asio::mutable_buffer raw_buff(raw_mem.get(), num_samps*sizeof(sc16_t)); @@ -218,7 +218,7 @@ size_t usrp2_impl::recv( return num_samps; } - if (type == "sc16"){ + if (type == "16sc"){ #ifdef HAVE_BIG_ENDIAN return recv_raw(buff, metadata); #else -- cgit v1.2.3 From 6e8473e6eef84875e2c3babb35732f8c3b2a0247 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 1 Mar 2010 11:50:14 -0800 Subject: Recv noise with uhd. --- firmware/microblaze/apps/txrx.c | 3 ++ host/apps/discover_usrps.cpp | 3 -- host/include/uhd/device_addr.hpp | 6 +-- host/include/uhd/usrp/dboard_id.hpp | 6 +-- host/lib/usrp/usrp2/dsp_impl.cpp | 12 +++++- host/lib/usrp/usrp2/fw_common.h | 1 + host/lib/usrp/usrp2/io_impl.cpp | 86 +++++++++++++++++++++++++------------ host/lib/usrp/usrp2/usrp2_impl.hpp | 3 ++ 8 files changed, 82 insertions(+), 38 deletions(-) diff --git a/firmware/microblaze/apps/txrx.c b/firmware/microblaze/apps/txrx.c index 1724284b0..dccb2bdc9 100644 --- a/firmware/microblaze/apps/txrx.c +++ b/firmware/microblaze/apps/txrx.c @@ -430,6 +430,8 @@ void handle_udp_ctrl_packet( ******************************************************************/ case USRP2_CTRL_ID_SETUP_THIS_DDC_FOR_ME_BRO: dsp_rx_regs->freq = ctrl_data_in->data.ddc_args.freq_word; + dsp_rx_regs->scale_iq = ctrl_data_in->data.ddc_args.scale_iq; + dsp_rx_regs->rx_mux = 0x00 | (0x01 << 2); //TODO fill in from control //setup the interp and half band filters { @@ -471,6 +473,7 @@ void handle_udp_ctrl_packet( case USRP2_CTRL_ID_SETUP_THIS_DUC_FOR_ME_BRO: dsp_tx_regs->freq = ctrl_data_in->data.duc_args.freq_word; dsp_tx_regs->scale_iq = ctrl_data_in->data.duc_args.scale_iq; + dsp_tx_regs->tx_mux = 0x01; //TODO fill in from control //setup the interp and half band filters { diff --git a/host/apps/discover_usrps.cpp b/host/apps/discover_usrps.cpp index 5172a4a26..20ac1f9ed 100644 --- a/host/apps/discover_usrps.cpp +++ b/host/apps/discover_usrps.cpp @@ -63,9 +63,6 @@ int main(int argc, char *argv[]){ std::cout << "-- USRP Device " << i << std::endl; std::cout << "--------------------------------------------------" << std::endl; std::cout << device_addrs[i] << std::endl << std::endl; - //make each device just to test (TODO: remove this) - uhd::device::sptr dev = uhd::device::make(device_addrs[i]); - std::cout << wax::cast((*dev)[uhd::DEVICE_PROP_MBOARD][uhd::MBOARD_PROP_NAME]) << std::endl; } return 0; diff --git a/host/include/uhd/device_addr.hpp b/host/include/uhd/device_addr.hpp index d02febd6c..ed538453a 100644 --- a/host/include/uhd/device_addr.hpp +++ b/host/include/uhd/device_addr.hpp @@ -56,9 +56,9 @@ namespace uhd{ * \param device_addr a device address instance * \return the string representation */ - struct device_addr{ - static std::string to_string(const device_addr_t &device_addr); - }; + namespace device_addr{ + std::string to_string(const device_addr_t &device_addr); + } } //namespace uhd diff --git a/host/include/uhd/usrp/dboard_id.hpp b/host/include/uhd/usrp/dboard_id.hpp index 8e904ff33..65e3d5707 100644 --- a/host/include/uhd/usrp/dboard_id.hpp +++ b/host/include/uhd/usrp/dboard_id.hpp @@ -28,9 +28,9 @@ enum dboard_id_t{ ID_BASIC_RX = 0x0001 }; -struct dboard_id{ - static std::string to_string(const dboard_id_t &id); -}; +namespace dboard_id{ + std::string to_string(const dboard_id_t &id); +} }} //namespace diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index 22c00d99a..e5c4a4245 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -36,6 +36,10 @@ static uint32_t calculate_freq_word_and_update_actual_freq(freq_t &freq, freq_t return freq_word; } +static uint32_t calculate_iq_scale_word(int16_t i, int16_t q){ + return ((i & 0xffff) << 16) | ((q & 0xffff) << 0); +} + void usrp2_impl::init_ddc_config(void){ //create the ddc in the rx dsp dict _rx_dsps["ddc0"] = wax_obj_proxy( @@ -61,6 +65,10 @@ void usrp2_impl::update_ddc_config(void){ calculate_freq_word_and_update_actual_freq(_ddc_freq, get_master_clock_freq()) ); out_data.data.ddc_args.decim = htonl(_ddc_decim); + static const uint32_t default_rx_scale_iq = 1024; + out_data.data.ddc_args.scale_iq = htonl( + calculate_iq_scale_word(default_rx_scale_iq, default_rx_scale_iq) + ); //send and recv usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); @@ -209,7 +217,9 @@ void usrp2_impl::update_duc_config(void){ calculate_freq_word_and_update_actual_freq(_duc_freq, get_master_clock_freq()) ); out_data.data.duc_args.interp = htonl(_duc_interp); - out_data.data.duc_args.scale_iq = htonl(scale); + out_data.data.duc_args.scale_iq = htonl( + calculate_iq_scale_word(scale, scale) + ); //send and recv usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index 3def8ddaa..aca0abb28 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -168,6 +168,7 @@ typedef struct{ struct { uint32_t freq_word; uint32_t decim; + uint32_t scale_iq; } ddc_args; struct { uint8_t enabled; diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index c9a7b5fa4..9c7a41e49 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -22,6 +22,7 @@ using namespace uhd; using namespace uhd::usrp; +namespace asio = boost::asio; /*********************************************************************** * Constants @@ -38,28 +39,28 @@ static const size_t max_vrt_header_words = 5; * Helper Functions **********************************************************************/ static inline void host_floats_to_usrp2_shorts( - int16_t *usrp2_shorts, + short *usrp2_shorts, const float *host_floats, size_t num_samps ){ for(size_t i = 0; i < num_samps; i++){ - usrp2_shorts[i] = htons(int16_t(host_floats[i]*float_scale_factor)); + usrp2_shorts[i] = htons(short(host_floats[i]*float_scale_factor)); } } static inline void usrp2_shorts_to_host_floats( float *host_floats, - const int16_t *usrp2_shorts, + const short *usrp2_shorts, size_t num_samps ){ for(size_t i = 0; i < num_samps; i++){ - host_floats[i] = float(ntohs(usrp2_shorts[i])/float_scale_factor); + host_floats[i] = float(short(ntohs(usrp2_shorts[i])))/float_scale_factor; } } static inline void host_shorts_to_usrp2_shorts( - int16_t *usrp2_shorts, - const int16_t *host_shorts, + short *usrp2_shorts, + const short *host_shorts, size_t num_samps ){ for(size_t i = 0; i < num_samps; i++){ @@ -68,8 +69,8 @@ static inline void host_shorts_to_usrp2_shorts( } static inline void usrp2_shorts_to_host_shorts( - int16_t *host_shorts, - const int16_t *usrp2_shorts, + short *host_shorts, + const short *usrp2_shorts, size_t num_samps ){ for(size_t i = 0; i < num_samps; i++){ @@ -102,16 +103,17 @@ size_t usrp2_impl::send_raw( } vrt_hdr_flags |= (metadata.start_of_burst)? (0x1 << 25) : 0; vrt_hdr_flags |= (metadata.end_of_burst)? (0x1 << 24) : 0; + num_vrt_hdr_words += asio::buffer_size(buff)/sizeof(uint32_t); //fill in complete header word vrt_hdr[0] = htonl(vrt_hdr_flags | ((_stream_id_to_packet_seq[metadata.stream_id]++ & 0xf) << 16) | - ((boost::asio::buffer_size(buff)/sizeof(uint32_t)) & 0xffff) + (num_vrt_hdr_words & 0xffff) ); //load the buffer vector size_t vrt_hdr_size = num_vrt_hdr_words*sizeof(uint32_t); - buffs[0] = boost::asio::buffer(&vrt_hdr, vrt_hdr_size); + buffs[0] = asio::buffer(&vrt_hdr, vrt_hdr_size); buffs[1] = buff; //send and return number of samples @@ -125,11 +127,33 @@ size_t usrp2_impl::recv_raw( const boost::asio::mutable_buffer &buff, uhd::metadata_t &metadata ){ + //handle the case where there is spillover + if (asio::buffer_size(_splillover_buff) != 0){ + size_t bytes_to_copy = std::min( + asio::buffer_size(_splillover_buff), + asio::buffer_size(buff) + ); + std::memcpy( + asio::buffer_cast(buff), + asio::buffer_cast(_splillover_buff), + bytes_to_copy + ); + _splillover_buff = asio::buffer( + asio::buffer_cast(_splillover_buff)+bytes_to_copy, + asio::buffer_size(_splillover_buff)-bytes_to_copy + ); + //std::cout << boost::format("Copied spillover %d samples") % (bytes_to_copy/sizeof(sc16_t)) << std::endl; + return bytes_to_copy/sizeof(sc16_t); + } + //load the buffer vector - std::vector buffs(2); + std::vector buffs(3); uint32_t vrt_hdr[max_vrt_header_words]; - buffs[0] = boost::asio::buffer(vrt_hdr, max_vrt_header_words); - buffs[1] = buff; + buffs[0] = asio::buffer(vrt_hdr, max_vrt_header_words*sizeof(uint32_t)); + buffs[1] = asio::buffer(//make sure its on a word boundary + buff, asio::buffer_size(buff) & ~(sizeof(uint32_t) - 1) + ); + buffs[2] = asio::buffer(_spillover_mem, _mtu); //receive into the buffers size_t bytes_recvd = _data_transport->recv(buffs); @@ -146,9 +170,15 @@ size_t usrp2_impl::recv_raw( metadata.time_spec.secs = ntohl(vrt_hdr[2]); metadata.time_spec.ticks = ntohl(vrt_hdr[3]); - //return the number of samples received - size_t num_words = vrt_header & 0xffff; - return (num_words*sizeof(uint32_t))/sizeof(sc16_t); + //extract the number of bytes received + size_t num_words = (vrt_header & 0xffff) - max_vrt_header_words; + size_t num_bytes = num_words*sizeof(uint32_t); + + //handle the case where spillover memory was used + size_t spillover_size = num_bytes - std::min(num_bytes, asio::buffer_size(buff)); + _splillover_buff = asio::buffer(_spillover_mem, spillover_size); + + return (num_bytes - spillover_size)/sizeof(sc16_t); } /*********************************************************************** @@ -160,13 +190,13 @@ size_t usrp2_impl::send( const std::string &type ){ if (type == "32fc"){ - size_t num_samps = boost::asio::buffer_size(buff)/sizeof(fc32_t); + size_t num_samps = asio::buffer_size(buff)/sizeof(fc32_t); boost::shared_array raw_mem(new sc16_t[num_samps]); boost::asio::mutable_buffer raw_buff(raw_mem.get(), num_samps*sizeof(sc16_t)); host_floats_to_usrp2_shorts( - boost::asio::buffer_cast(raw_buff), - boost::asio::buffer_cast(buff), + asio::buffer_cast(raw_buff), + asio::buffer_cast(buff), num_samps*2 //double for complex ); @@ -177,13 +207,13 @@ size_t usrp2_impl::send( #ifdef HAVE_BIG_ENDIAN return send_raw(buff, metadata); #else - size_t num_samps = boost::asio::buffer_size(buff)/sizeof(sc16_t); + size_t num_samps = asio::buffer_size(buff)/sizeof(sc16_t); boost::shared_array raw_mem(new sc16_t[num_samps]); boost::asio::mutable_buffer raw_buff(raw_mem.get(), num_samps*sizeof(sc16_t)); host_shorts_to_usrp2_shorts( - boost::asio::buffer_cast(raw_buff), - boost::asio::buffer_cast(buff), + asio::buffer_cast(raw_buff), + asio::buffer_cast(buff), num_samps*2 //double for complex ); @@ -203,15 +233,15 @@ size_t usrp2_impl::recv( const std::string &type ){ if (type == "32fc"){ - size_t num_samps = boost::asio::buffer_size(buff)/sizeof(fc32_t); + size_t num_samps = asio::buffer_size(buff)/sizeof(fc32_t); boost::shared_array raw_mem(new sc16_t[num_samps]); boost::asio::mutable_buffer raw_buff(raw_mem.get(), num_samps*sizeof(sc16_t)); num_samps = recv_raw(raw_buff, metadata); usrp2_shorts_to_host_floats( - boost::asio::buffer_cast(buff), - boost::asio::buffer_cast(raw_buff), + asio::buffer_cast(buff), + asio::buffer_cast(raw_buff), num_samps*2 //double for complex ); @@ -222,15 +252,15 @@ size_t usrp2_impl::recv( #ifdef HAVE_BIG_ENDIAN return recv_raw(buff, metadata); #else - size_t num_samps = boost::asio::buffer_size(buff)/sizeof(sc16_t); + size_t num_samps = asio::buffer_size(buff)/sizeof(sc16_t); boost::shared_array raw_mem(new sc16_t[num_samps]); boost::asio::mutable_buffer raw_buff(raw_mem.get(), num_samps*sizeof(sc16_t)); num_samps = recv_raw(raw_buff, metadata); usrp2_shorts_to_host_shorts( - boost::asio::buffer_cast(buff), - boost::asio::buffer_cast(raw_buff), + asio::buffer_cast(buff), + asio::buffer_cast(raw_buff), num_samps*2 //double for complex ); diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 9a4c42d42..47b01d1b1 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -106,6 +106,9 @@ private: size_t send_raw(const boost::asio::const_buffer &, const uhd::metadata_t &); size_t recv_raw(const boost::asio::mutable_buffer &, uhd::metadata_t &); uhd::dict _stream_id_to_packet_seq; + static const size_t _mtu = 1500; + uint8_t _spillover_mem[_mtu]; + boost::asio::mutable_buffer _splillover_buff; //udp transports for control and data uhd::transport::udp::sptr _ctrl_transport; -- cgit v1.2.3 From 451067295399e357d73c9bfdeef5f2ad040e0243 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 1 Mar 2010 16:13:30 -0800 Subject: Send the number of samples per datagram over the control. Worked on the io impl for usrp2 (added loop unrolls and 32 bit buffers). Added some vrt rx constants to the fw common used by host and fw. Removed the MTU prop and added a general device prop for num samples. --- firmware/microblaze/apps/txrx.c | 45 ++++------- host/include/uhd/props.hpp | 5 +- host/include/uhd/utils.hpp | 5 ++ host/lib/usrp/usrp2/dsp_impl.cpp | 16 ++-- host/lib/usrp/usrp2/fw_common.h | 5 ++ host/lib/usrp/usrp2/io_impl.cpp | 153 +++++++++++++++++++++--------------- host/lib/usrp/usrp2/mboard_impl.cpp | 11 +-- host/lib/usrp/usrp2/usrp2_impl.cpp | 15 +++- host/lib/usrp/usrp2/usrp2_impl.hpp | 11 ++- 9 files changed, 152 insertions(+), 114 deletions(-) diff --git a/firmware/microblaze/apps/txrx.c b/firmware/microblaze/apps/txrx.c index dccb2bdc9..e4e40e7e0 100644 --- a/firmware/microblaze/apps/txrx.c +++ b/firmware/microblaze/apps/txrx.c @@ -457,6 +457,8 @@ void handle_udp_ctrl_packet( case USRP2_CTRL_ID_CONFIGURE_STREAMING_FOR_ME_BRO: time_secs = ctrl_data_in->data.streaming.secs; time_ticks = ctrl_data_in->data.streaming.ticks; + streaming_items_per_frame = ctrl_data_in->data.streaming.samples; + if (ctrl_data_in->data.streaming.enabled == 0){ stop_rx_cmd(); } @@ -518,8 +520,15 @@ eth_pkt_inspector(dbsm_t *sm, int bufno) //------------------------------------------------------------------ -#define VRT_HEADER_WORDS 5 -#define VRT_TRAILER_WORDS 0 +static uint16_t get_vrt_packet_words(void){ + return streaming_items_per_frame + \ + USRP2_HOST_RX_VRT_HEADER_WORDS32 + \ + USRP2_HOST_RX_VRT_TRAILER_WORDS32; +} + +static bool vrt_has_trailer(void){ + return USRP2_HOST_RX_VRT_TRAILER_WORDS32 > 0; +} void restart_streaming(void) @@ -530,10 +539,10 @@ restart_streaming(void) sr_rx_ctrl->clear_overrun = 1; // reset sr_rx_ctrl->vrt_header = (0 | VRTH_PT_IF_DATA_WITH_SID - | ((VRT_TRAILER_WORDS)? VRTH_HAS_TRAILER : 0) + | (vrt_has_trailer()? VRTH_HAS_TRAILER : 0) | VRTH_TSI_OTHER | VRTH_TSF_SAMPLE_CNT - | (VRT_HEADER_WORDS+streaming_items_per_frame+VRT_TRAILER_WORDS)); + ); sr_rx_ctrl->vrt_stream_id = 0; sr_rx_ctrl->vrt_trailer = 0; @@ -595,8 +604,9 @@ start_rx_streaming_cmd(void) } mem _AL4; memset(&mem, 0, sizeof(mem)); - streaming_items_per_frame = (1500)/sizeof(uint32_t) - (DSP_TX_FIRST_LINE + VRT_HEADER_WORDS + VRT_TRAILER_WORDS); //FIXME - mem.ctrl_word = (VRT_HEADER_WORDS+streaming_items_per_frame+VRT_TRAILER_WORDS)*sizeof(uint32_t) | 1 << 16; + printf("samples per frame: %d\n", streaming_items_per_frame); + printf("words in a vrt packet %d\n", get_vrt_packet_words()); + mem.ctrl_word = get_vrt_packet_words()*sizeof(uint32_t) | 1 << 16; memcpy_wa(buffer_ram(DSP_RX_BUF_0), &mem, sizeof(mem)); memcpy_wa(buffer_ram(DSP_RX_BUF_1), &mem, sizeof(mem)); @@ -653,25 +663,6 @@ stop_rx_cmd(void) } - -/*static void -setup_tx() -{ - sr_tx_ctrl->clear_state = 1; - bp_clear_buf(DSP_TX_BUF_0); - bp_clear_buf(DSP_TX_BUF_1); - - int tx_scale = 256; - int interp = 32; - - // setup some defaults - - dsp_tx_regs->freq = 0; - dsp_tx_regs->scale_iq = (tx_scale << 16) | tx_scale; - dsp_tx_regs->interp_rate = interp; -}*/ - - #if (FW_SETS_SEQNO) /* * Debugging ONLY. This will be handled by the tx_protocol_engine. @@ -760,10 +751,6 @@ main(void) // tell app_common that this dbsm could be sending to the ethernet ac_could_be_sending_to_eth = &dsp_rx_sm; - - // program tx registers - //setup_tx(); - // kick off the state machine dbsm_start(&dsp_tx_sm); diff --git a/host/include/uhd/props.hpp b/host/include/uhd/props.hpp index 2b6daf6c5..cf301d4bd 100644 --- a/host/include/uhd/props.hpp +++ b/host/include/uhd/props.hpp @@ -65,7 +65,9 @@ namespace uhd{ enum device_prop_t{ DEVICE_PROP_NAME, //ro, std::string DEVICE_PROP_MBOARD, //ro, wax::obj - DEVICE_PROP_MBOARD_NAMES //ro, prop_names_t + DEVICE_PROP_MBOARD_NAMES, //ro, prop_names_t + DEVICE_PROP_MAX_RX_SAMPLES, //ro, size_t + DEVICE_PROP_MAX_TX_SAMPLES //ro, size_t }; /*! @@ -77,7 +79,6 @@ namespace uhd{ enum mboard_prop_t{ MBOARD_PROP_NAME, //ro, std::string MBOARD_PROP_OTHERS, //ro, prop_names_t - MBOARD_PROP_MTU, //ro, size_t MBOARD_PROP_CLOCK_RATE, //ro, freq_t MBOARD_PROP_RX_DSP, //ro, wax::obj MBOARD_PROP_RX_DSP_NAMES, //ro, prop_names_t diff --git a/host/include/uhd/utils.hpp b/host/include/uhd/utils.hpp index 4331aba7e..9bbdc83c9 100644 --- a/host/include/uhd/utils.hpp +++ b/host/include/uhd/utils.hpp @@ -57,6 +57,11 @@ namespace std{ return last != std::find(first, last, elem); } + template + bool has(const V &vector, const T &elem){ + return has(vector.begin(), vector.end(), elem); + } + template T sum(const T &a, const T &b){ return a + b; diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index e5c4a4245..a57f5ff2d 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -48,7 +48,7 @@ void usrp2_impl::init_ddc_config(void){ ); //initial config and update - _ddc_decim = 16; + _ddc_decim = 64; _ddc_freq = 0; update_ddc_config(); @@ -82,6 +82,12 @@ void usrp2_impl::update_ddc_enabled(void){ out_data.data.streaming.enabled = (_ddc_enabled)? 1 : 0; out_data.data.streaming.secs = htonl(_ddc_stream_at.secs); out_data.data.streaming.ticks = htonl(_ddc_stream_at.ticks); + out_data.data.streaming.samples = htonl( + _mtu/sizeof(uint32_t) - + USRP2_HOST_RX_VRT_HEADER_WORDS32 - + USRP2_HOST_RX_VRT_TRAILER_WORDS32 - + ((2 + 14 + 20 + 8)/sizeof(uint32_t)) //size of headers (pad, eth, ip, udp) + ); //send and recv usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); @@ -151,8 +157,7 @@ void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){ if (key_name == "decim"){ size_t new_decim = wax::cast(val); ASSERT_THROW(std::has( - _allowed_decim_and_interp_rates.begin(), - _allowed_decim_and_interp_rates.end(), + _allowed_decim_and_interp_rates, new_decim )); _ddc_decim = new_decim; //shadow @@ -196,7 +201,7 @@ void usrp2_impl::init_duc_config(void){ ); //initial config and update - _duc_interp = 16; + _duc_interp = 64; _duc_freq = 0; update_duc_config(); } @@ -280,8 +285,7 @@ void usrp2_impl::duc_set(const wax::obj &key, const wax::obj &val){ if (key_name == "interp"){ size_t new_interp = wax::cast(val); ASSERT_THROW(std::has( - _allowed_decim_and_interp_rates.begin(), - _allowed_decim_and_interp_rates.end(), + _allowed_decim_and_interp_rates, new_interp )); _duc_interp = new_interp; //shadow diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index aca0abb28..8e4b2ba35 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -27,6 +27,10 @@ extern "C" { #endif +// size of the vrt header and trailer to the host +#define USRP2_HOST_RX_VRT_HEADER_WORDS32 5 +#define USRP2_HOST_RX_VRT_TRAILER_WORDS32 1 //FIXME fpga sets wrong header size when no trailer present + // udp ports for the usrp2 communication // Dynamic and/or private ports: 49152-65535 #define USRP2_UDP_CTRL_PORT 49152 @@ -175,6 +179,7 @@ typedef struct{ uint8_t _pad[3]; uint32_t secs; uint32_t ticks; + uint32_t samples; } streaming; struct { uint32_t freq_word; diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 9c7a41e49..8b45a708a 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -16,7 +16,6 @@ // #include -#include #include #include "usrp2_impl.hpp" @@ -27,55 +26,80 @@ namespace asio = boost::asio; /*********************************************************************** * Constants **********************************************************************/ -typedef std::complex fc32_t; -typedef std::complex sc16_t; +typedef std::complex fc32_t; +typedef std::complex sc16_t; -static const float float_scale_factor = pow(2.0, 15); - -//max length with header, stream id, seconds, fractional seconds -static const size_t max_vrt_header_words = 5; +static const float shorts_per_float = pow(2.0, 15); +static const float floats_per_short = 1.0/shorts_per_float; /*********************************************************************** * Helper Functions **********************************************************************/ -static inline void host_floats_to_usrp2_shorts( - short *usrp2_shorts, - const float *host_floats, +void usrp2_impl::io_init(void){ + //initially empty spillover buffer + _splillover_buff = asio::buffer(_spillover_mem, 0); + + //send a small data packet so the usrp2 knows the udp source port + uint32_t zero_data = 0; + _data_transport->send(boost::asio::buffer(&zero_data, sizeof(zero_data))); +} + +#define unrolled_loop(__i, __len, __inst) {\ + size_t __i = 0; \ + while(__i < (__len & ~0x7)){ \ + __inst; __i++; __inst; __i++; \ + __inst; __i++; __inst; __i++; \ + __inst; __i++; __inst; __i++; \ + __inst; __i++; __inst; __i++; \ + } \ + while(__i < __len){ \ + __inst; __i++;\ + } \ +} + +static inline void host_floats_to_usrp2_items( + uint32_t *usrp2_items, + const fc32_t *host_floats, size_t num_samps ){ - for(size_t i = 0; i < num_samps; i++){ - usrp2_shorts[i] = htons(short(host_floats[i]*float_scale_factor)); - } + unrolled_loop(i, num_samps,{ + int16_t real = host_floats[i].real()*shorts_per_float; + int16_t imag = host_floats[i].imag()*shorts_per_float; + usrp2_items[i] = htonl(((real << 16) & 0xffff) | ((imag << 0) & 0xffff)); + }); } -static inline void usrp2_shorts_to_host_floats( - float *host_floats, - const short *usrp2_shorts, +static inline void usrp2_items_to_host_floats( + fc32_t *host_floats, + const uint32_t *usrp2_items, size_t num_samps ){ - for(size_t i = 0; i < num_samps; i++){ - host_floats[i] = float(short(ntohs(usrp2_shorts[i])))/float_scale_factor; - } + unrolled_loop(i, num_samps,{ + uint32_t item = ntohl(usrp2_items[i]); + int16_t real = (item >> 16) & 0xffff; + int16_t imag = (item >> 0) & 0xffff; + host_floats[i] = fc32_t(real*floats_per_short, imag*floats_per_short); + }); } -static inline void host_shorts_to_usrp2_shorts( - short *usrp2_shorts, - const short *host_shorts, +static inline void host_items_to_usrp2_items( + uint32_t *usrp2_items, + const uint32_t *host_items, size_t num_samps ){ - for(size_t i = 0; i < num_samps; i++){ - usrp2_shorts[i] = htons(host_shorts[i]); - } + unrolled_loop(i, num_samps, + usrp2_items[i] = htonl(host_items[i]) + ); } -static inline void usrp2_shorts_to_host_shorts( - short *host_shorts, - const short *usrp2_shorts, +static inline void usrp2_items_to_host_items( + uint32_t *host_items, + const uint32_t *usrp2_items, size_t num_samps ){ - for(size_t i = 0; i < num_samps; i++){ - host_shorts[i] = ntohs(usrp2_shorts[i]); - } + unrolled_loop(i, num_samps, + host_items[i] = ntohl(usrp2_items[i]) + ); } /*********************************************************************** @@ -86,7 +110,7 @@ size_t usrp2_impl::send_raw( const uhd::metadata_t &metadata ){ std::vector buffs(2); - uint32_t vrt_hdr[max_vrt_header_words]; + uint32_t vrt_hdr[7]; //max size uint32_t vrt_hdr_flags = 0; size_t num_vrt_hdr_words = 1; @@ -107,7 +131,7 @@ size_t usrp2_impl::send_raw( //fill in complete header word vrt_hdr[0] = htonl(vrt_hdr_flags | - ((_stream_id_to_packet_seq[metadata.stream_id]++ & 0xf) << 16) | + ((_tx_stream_id_to_packet_seq[metadata.stream_id]++ & 0xf) << 16) | (num_vrt_hdr_words & 0xffff) ); @@ -148,18 +172,16 @@ size_t usrp2_impl::recv_raw( //load the buffer vector std::vector buffs(3); - uint32_t vrt_hdr[max_vrt_header_words]; - buffs[0] = asio::buffer(vrt_hdr, max_vrt_header_words*sizeof(uint32_t)); - buffs[1] = asio::buffer(//make sure its on a word boundary - buff, asio::buffer_size(buff) & ~(sizeof(uint32_t) - 1) - ); + uint32_t vrt_hdr[USRP2_HOST_RX_VRT_HEADER_WORDS32]; + buffs[0] = asio::buffer(vrt_hdr, sizeof(vrt_hdr)); + buffs[1] = buff; buffs[2] = asio::buffer(_spillover_mem, _mtu); //receive into the buffers size_t bytes_recvd = _data_transport->recv(buffs); //failure case - if (bytes_recvd < max_vrt_header_words*sizeof(uint32_t)) return 0; + if (bytes_recvd < sizeof(vrt_hdr)) return 0; //unpack the vrt header metadata = uhd::metadata_t(); @@ -170,8 +192,15 @@ size_t usrp2_impl::recv_raw( metadata.time_spec.secs = ntohl(vrt_hdr[2]); metadata.time_spec.ticks = ntohl(vrt_hdr[3]); + size_t my_seq = (vrt_header >> 16) & 0xf; + //std::cout << "seq " << my_seq << std::endl; + if (my_seq != ((_rx_stream_id_to_packet_seq[metadata.stream_id]+1) & 0xf)) std::cout << "bad seq " << my_seq << std::endl; + _rx_stream_id_to_packet_seq[metadata.stream_id] = my_seq; + //extract the number of bytes received - size_t num_words = (vrt_header & 0xffff) - max_vrt_header_words; + size_t num_words = (vrt_header & 0xffff); + num_words -= USRP2_HOST_RX_VRT_HEADER_WORDS32; + num_words -= USRP2_HOST_RX_VRT_TRAILER_WORDS32; size_t num_bytes = num_words*sizeof(uint32_t); //handle the case where spillover memory was used @@ -191,13 +220,12 @@ size_t usrp2_impl::send( ){ if (type == "32fc"){ size_t num_samps = asio::buffer_size(buff)/sizeof(fc32_t); - boost::shared_array raw_mem(new sc16_t[num_samps]); - boost::asio::mutable_buffer raw_buff(raw_mem.get(), num_samps*sizeof(sc16_t)); + boost::asio::mutable_buffer raw_buff(_tmp_send_mem, num_samps*sizeof(sc16_t)); - host_floats_to_usrp2_shorts( - asio::buffer_cast(raw_buff), - asio::buffer_cast(buff), - num_samps*2 //double for complex + host_floats_to_usrp2_items( + asio::buffer_cast(raw_buff), + asio::buffer_cast(buff), + num_samps ); return send_raw(raw_buff, metadata); @@ -208,13 +236,12 @@ size_t usrp2_impl::send( return send_raw(buff, metadata); #else size_t num_samps = asio::buffer_size(buff)/sizeof(sc16_t); - boost::shared_array raw_mem(new sc16_t[num_samps]); - boost::asio::mutable_buffer raw_buff(raw_mem.get(), num_samps*sizeof(sc16_t)); + boost::asio::mutable_buffer raw_buff(_tmp_send_mem, num_samps*sizeof(sc16_t)); - host_shorts_to_usrp2_shorts( - asio::buffer_cast(raw_buff), - asio::buffer_cast(buff), - num_samps*2 //double for complex + host_items_to_usrp2_items( + asio::buffer_cast(raw_buff), + asio::buffer_cast(buff), + num_samps ); return send_raw(raw_buff, metadata); @@ -234,15 +261,14 @@ size_t usrp2_impl::recv( ){ if (type == "32fc"){ size_t num_samps = asio::buffer_size(buff)/sizeof(fc32_t); - boost::shared_array raw_mem(new sc16_t[num_samps]); - boost::asio::mutable_buffer raw_buff(raw_mem.get(), num_samps*sizeof(sc16_t)); + boost::asio::mutable_buffer raw_buff(_tmp_recv_mem, num_samps*sizeof(sc16_t)); num_samps = recv_raw(raw_buff, metadata); - usrp2_shorts_to_host_floats( - asio::buffer_cast(buff), - asio::buffer_cast(raw_buff), - num_samps*2 //double for complex + usrp2_items_to_host_floats( + asio::buffer_cast(buff), + asio::buffer_cast(raw_buff), + num_samps ); return num_samps; @@ -253,15 +279,14 @@ size_t usrp2_impl::recv( return recv_raw(buff, metadata); #else size_t num_samps = asio::buffer_size(buff)/sizeof(sc16_t); - boost::shared_array raw_mem(new sc16_t[num_samps]); - boost::asio::mutable_buffer raw_buff(raw_mem.get(), num_samps*sizeof(sc16_t)); + boost::asio::mutable_buffer raw_buff(_tmp_recv_mem, num_samps*sizeof(sc16_t)); num_samps = recv_raw(raw_buff, metadata); - usrp2_shorts_to_host_shorts( - asio::buffer_cast(buff), - asio::buffer_cast(raw_buff), - num_samps*2 //double for complex + usrp2_items_to_host_items( + asio::buffer_cast(buff), + asio::buffer_cast(raw_buff), + num_samps ); return num_samps; diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index cc73b229c..8e682a675 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -82,6 +82,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ return; case MBOARD_PROP_RX_DBOARD: + ASSERT_THROW(_rx_dboards.has_key(name)); val = _rx_dboards[name].get_link(); return; @@ -90,6 +91,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ return; case MBOARD_PROP_TX_DBOARD: + ASSERT_THROW(_tx_dboards.has_key(name)); val = _tx_dboards[name].get_link(); return; @@ -97,17 +99,12 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ val = prop_names_t(_tx_dboards.get_keys()); return; - case MBOARD_PROP_MTU: - // FIXME we dont know the real MTU... - // give them something to fragment about - val = size_t(1500); - return; - case MBOARD_PROP_CLOCK_RATE: val = freq_t(get_master_clock_freq()); return; case MBOARD_PROP_RX_DSP: + ASSERT_THROW(_rx_dsps.has_key(name)); val = _rx_dsps[name].get_link(); return; @@ -116,6 +113,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ return; case MBOARD_PROP_TX_DSP: + ASSERT_THROW(_tx_dsps.has_key(name)); val = _tx_dsps[name].get_link(); return; @@ -183,7 +181,6 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){ case MBOARD_PROP_NAME: case MBOARD_PROP_OTHERS: - case MBOARD_PROP_MTU: case MBOARD_PROP_CLOCK_RATE: case MBOARD_PROP_RX_DSP: case MBOARD_PROP_RX_DSP_NAMES: diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 06876d241..700f94ae1 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -133,9 +133,8 @@ usrp2_impl::usrp2_impl( //init the tx and rx dboards (do last) dboard_init(); - //send a small data packet so the usrp2 knows the udp source port - uint32_t zero_data = 0; - _data_transport->send(boost::asio::buffer(&zero_data, sizeof(zero_data))); + //init the send and recv io + io_init(); } @@ -197,12 +196,22 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){ return; case DEVICE_PROP_MBOARD: + ASSERT_THROW(_mboards.has_key(name)); val = _mboards[name].get_link(); return; case DEVICE_PROP_MBOARD_NAMES: val = prop_names_t(_mboards.get_keys()); return; + + case DEVICE_PROP_MAX_RX_SAMPLES: + val = size_t(_max_samples_per_packet); + return; + + case DEVICE_PROP_MAX_TX_SAMPLES: + val = size_t(_max_samples_per_packet); + return; + } } diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 47b01d1b1..43f32c6e6 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -105,10 +105,15 @@ private: //the raw io interface (samples are in the usrp2 native format) size_t send_raw(const boost::asio::const_buffer &, const uhd::metadata_t &); size_t recv_raw(const boost::asio::mutable_buffer &, uhd::metadata_t &); - uhd::dict _stream_id_to_packet_seq; - static const size_t _mtu = 1500; - uint8_t _spillover_mem[_mtu]; + uhd::dict _tx_stream_id_to_packet_seq; + uhd::dict _rx_stream_id_to_packet_seq; + static const size_t _mtu = 1500; //FIXME we have no idea + static const size_t _max_samples_per_packet = _mtu/sizeof(uint32_t); + uint32_t _tmp_send_mem[_mtu/sizeof(uint32_t)]; + uint32_t _tmp_recv_mem[_mtu/sizeof(uint32_t)]; + uint32_t _spillover_mem[_mtu/sizeof(uint32_t)]; boost::asio::mutable_buffer _splillover_buff; + void io_init(void); //udp transports for control and data uhd::transport::udp::sptr _ctrl_transport; -- cgit v1.2.3 From 13bd67b4949a91df5e6696e708c935266b14c502 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 2 Mar 2010 14:48:11 -0800 Subject: The net common is too slow in usrp2 firmware to figure out if its vrt data. Added a custom function to tell if a packet is vrt data, seems to be feeding fast enough at this rate... Fixed some buffer size calculation logic. --- firmware/microblaze/apps/txrx.c | 28 ++++++++++++++++------------ firmware/microblaze/lib/net_common.c | 11 +++++++++++ firmware/microblaze/lib/net_common.h | 1 + host/lib/usrp/usrp2/dsp_impl.cpp | 7 +------ host/lib/usrp/usrp2/io_impl.cpp | 11 ++++++----- host/lib/usrp/usrp2/usrp2_impl.hpp | 7 ++++++- 6 files changed, 41 insertions(+), 24 deletions(-) diff --git a/firmware/microblaze/apps/txrx.c b/firmware/microblaze/apps/txrx.c index e4e40e7e0..9c3caa4f2 100644 --- a/firmware/microblaze/apps/txrx.c +++ b/firmware/microblaze/apps/txrx.c @@ -158,19 +158,10 @@ static struct ip_addr get_my_ip_addr(void){ return addr; } -static bool _is_data; - void handle_udp_data_packet( struct socket_address src, struct socket_address dst, unsigned char *payload, int payload_len ){ - //forward this data to the dsp when the payload is sufficient - //the small payload is used to give the device the udp source port - if (payload_len > sizeof(uint32_t)){ - _is_data = true; - return; - } - //its a tiny payload, load the fast-path variables fp_mac_addr_src = get_my_eth_mac_addr(); arp_cache_lookup_mac(&src.addr, &fp_mac_addr_dst); @@ -513,9 +504,18 @@ void handle_udp_ctrl_packet( static bool eth_pkt_inspector(dbsm_t *sm, int bufno) { - _is_data = false; - handle_eth_packet(buffer_ram(bufno), buffer_pool_status->last_line[bufno] - 3); - return !_is_data; + //extract buffer point and length + uint32_t *buff = (uint32_t *)buffer_ram(bufno); + size_t len = buffer_pool_status->last_line[bufno] - 3; + + //treat this as fast-path data? + if (is_udp_packet_with_vrt(buff, len, USRP2_UDP_DATA_PORT)){ + return false; + } + + //pass it to the slow-path handler + handle_eth_packet(buff, len); + return true; } //------------------------------------------------------------------ @@ -751,6 +751,10 @@ main(void) // tell app_common that this dbsm could be sending to the ethernet ac_could_be_sending_to_eth = &dsp_rx_sm; + sr_tx_ctrl->clear_state = 1; + bp_clear_buf(DSP_TX_BUF_0); + bp_clear_buf(DSP_TX_BUF_1); + // kick off the state machine dbsm_start(&dsp_tx_sm); diff --git a/firmware/microblaze/lib/net_common.c b/firmware/microblaze/lib/net_common.c index 693502d18..ab7aadca9 100644 --- a/firmware/microblaze/lib/net_common.c +++ b/firmware/microblaze/lib/net_common.c @@ -378,6 +378,17 @@ handle_arp_packet(struct arp_eth_ipv4 *p, size_t size) } } +bool is_udp_packet_with_vrt(uint32_t *p, size_t nlines, int port){ + struct ip_hdr *ip = (struct ip_hdr *)(p + 4); + struct udp_hdr *udp = (struct udp_hdr *)(((char *)ip) + IP_HLEN); + uint32_t *payload = (uint32_t *)(((char *)udp) + UDP_HLEN); + return \ + (p[3] & 0xffff) == ETHERTYPE_IPV4 && + IPH_PROTO(ip) == IP_PROTO_UDP && + udp->dest == port && + payload[0] != 0; //must be non zero vrt header +} + void handle_eth_packet(uint32_t *p, size_t nlines) { diff --git a/firmware/microblaze/lib/net_common.h b/firmware/microblaze/lib/net_common.h index cfba43412..1a7052f71 100644 --- a/firmware/microblaze/lib/net_common.h +++ b/firmware/microblaze/lib/net_common.h @@ -56,5 +56,6 @@ void send_udp_pkt(int src_port, struct socket_address dst, void handle_eth_packet(uint32_t *p, size_t nlines); +bool is_udp_packet_with_vrt(uint32_t *p, size_t nlines, int port); #endif /* INCLUDED_NET_COMMON_H */ diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index a57f5ff2d..8fdfd685f 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -82,12 +82,7 @@ void usrp2_impl::update_ddc_enabled(void){ out_data.data.streaming.enabled = (_ddc_enabled)? 1 : 0; out_data.data.streaming.secs = htonl(_ddc_stream_at.secs); out_data.data.streaming.ticks = htonl(_ddc_stream_at.ticks); - out_data.data.streaming.samples = htonl( - _mtu/sizeof(uint32_t) - - USRP2_HOST_RX_VRT_HEADER_WORDS32 - - USRP2_HOST_RX_VRT_TRAILER_WORDS32 - - ((2 + 14 + 20 + 8)/sizeof(uint32_t)) //size of headers (pad, eth, ip, udp) - ); + out_data.data.streaming.samples = htonl(_max_samples_per_packet); //send and recv usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 8b45a708a..0ca2409c3 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -127,12 +127,11 @@ size_t usrp2_impl::send_raw( } vrt_hdr_flags |= (metadata.start_of_burst)? (0x1 << 25) : 0; vrt_hdr_flags |= (metadata.end_of_burst)? (0x1 << 24) : 0; - num_vrt_hdr_words += asio::buffer_size(buff)/sizeof(uint32_t); //fill in complete header word vrt_hdr[0] = htonl(vrt_hdr_flags | ((_tx_stream_id_to_packet_seq[metadata.stream_id]++ & 0xf) << 16) | - (num_vrt_hdr_words & 0xffff) + ((num_vrt_hdr_words + asio::buffer_size(buff)/sizeof(uint32_t)) & 0xffff) ); //load the buffer vector @@ -151,6 +150,8 @@ size_t usrp2_impl::recv_raw( const boost::asio::mutable_buffer &buff, uhd::metadata_t &metadata ){ + metadata = metadata_t(); //clear metadata + //handle the case where there is spillover if (asio::buffer_size(_splillover_buff) != 0){ size_t bytes_to_copy = std::min( @@ -198,9 +199,9 @@ size_t usrp2_impl::recv_raw( _rx_stream_id_to_packet_seq[metadata.stream_id] = my_seq; //extract the number of bytes received - size_t num_words = (vrt_header & 0xffff); - num_words -= USRP2_HOST_RX_VRT_HEADER_WORDS32; - num_words -= USRP2_HOST_RX_VRT_TRAILER_WORDS32; + size_t num_words = (vrt_header & 0xffff) - + USRP2_HOST_RX_VRT_HEADER_WORDS32 - + USRP2_HOST_RX_VRT_TRAILER_WORDS32; size_t num_bytes = num_words*sizeof(uint32_t); //handle the case where spillover memory was used diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 43f32c6e6..037aed477 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -108,7 +108,12 @@ private: uhd::dict _tx_stream_id_to_packet_seq; uhd::dict _rx_stream_id_to_packet_seq; static const size_t _mtu = 1500; //FIXME we have no idea - static const size_t _max_samples_per_packet = _mtu/sizeof(uint32_t); + static const size_t _max_samples_per_packet = + _mtu/sizeof(uint32_t) - + USRP2_HOST_RX_VRT_HEADER_WORDS32 - + USRP2_HOST_RX_VRT_TRAILER_WORDS32 - + ((2 + 14 + 20 + 8)/sizeof(uint32_t)) //size of headers (pad, eth, ip, udp) + ; uint32_t _tmp_send_mem[_mtu/sizeof(uint32_t)]; uint32_t _tmp_recv_mem[_mtu/sizeof(uint32_t)]; uint32_t _spillover_mem[_mtu/sizeof(uint32_t)]; -- cgit v1.2.3 From 4efafcc2e20b9a980800a979edf5ea7a493b6462 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 2 Mar 2010 22:07:17 -0800 Subject: Expanded the UDP api: We can make simple udp transports for discovery and control. We can support a udp zero copy transport (currently just asio). Reworked the io_impl for usrp2 to work with the zero copy api. So far, all of this untested other than compiling. A cut-down vrt library is in the works to simplify the io impl. --- host/include/uhd/transport/CMakeLists.txt | 4 +- host/include/uhd/transport/smart_buffer.hpp | 45 ++++++ host/include/uhd/transport/udp.hpp | 76 ---------- host/include/uhd/transport/udp_simple.hpp | 79 +++++++++++ host/include/uhd/transport/udp_zero_copy.hpp | 76 ++++++++++ host/include/uhd/usrp/usrp2.hpp | 10 ++ host/lib/CMakeLists.txt | 9 +- host/lib/transport/udp.cpp | 98 ------------- host/lib/transport/udp_simple.cpp | 133 ++++++++++++++++++ host/lib/transport/udp_zero_copy_none.cpp | 117 ++++++++++++++++ host/lib/usrp/usrp2/io_impl.cpp | 202 +++++++++++---------------- host/lib/usrp/usrp2/usrp2_impl.cpp | 18 ++- host/lib/usrp/usrp2/usrp2_impl.hpp | 24 ++-- 13 files changed, 577 insertions(+), 314 deletions(-) create mode 100644 host/include/uhd/transport/smart_buffer.hpp delete mode 100644 host/include/uhd/transport/udp.hpp create mode 100644 host/include/uhd/transport/udp_simple.hpp create mode 100644 host/include/uhd/transport/udp_zero_copy.hpp delete mode 100644 host/lib/transport/udp.cpp create mode 100644 host/lib/transport/udp_simple.cpp create mode 100644 host/lib/transport/udp_zero_copy_none.cpp diff --git a/host/include/uhd/transport/CMakeLists.txt b/host/include/uhd/transport/CMakeLists.txt index b786eb945..ba8b33cc5 100644 --- a/host/include/uhd/transport/CMakeLists.txt +++ b/host/include/uhd/transport/CMakeLists.txt @@ -17,6 +17,8 @@ INSTALL(FILES - udp.hpp + smart_buffer.hpp + udp_simple.hpp + udp_zero_copy.hpp DESTINATION ${HEADER_DIR}/uhd/transport ) diff --git a/host/include/uhd/transport/smart_buffer.hpp b/host/include/uhd/transport/smart_buffer.hpp new file mode 100644 index 000000000..914c02f50 --- /dev/null +++ b/host/include/uhd/transport/smart_buffer.hpp @@ -0,0 +1,45 @@ +// +// 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 + +#ifndef INCLUDED_UHD_TRANSPORT_SMART_BUFFER_HPP +#define INCLUDED_UHD_TRANSPORT_SMART_BUFFER_HPP + +namespace uhd{ namespace transport{ + +/*! + * A buffer that knows how to free itself: + * + * This is just the smart buffer interface. + * A transport implementation will have its own + * internal (custom) smart buffer implementation. + * + * A smart buffer contains a boost asio const buffer. + * On destruction, the buffer contents will be freed. + */ +class smart_buffer : boost::noncopyable{ +public: + typedef boost::shared_ptr sptr; + virtual const boost::asio::const_buffer &get(void) const = 0; +}; + +}} //namespace + +#endif /* INCLUDED_UHD_TRANSPORT_SMART_BUFFER_HPP */ diff --git a/host/include/uhd/transport/udp.hpp b/host/include/uhd/transport/udp.hpp deleted file mode 100644 index 8c6fb096f..000000000 --- a/host/include/uhd/transport/udp.hpp +++ /dev/null @@ -1,76 +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 -#include -#include - -#ifndef INCLUDED_UHD_TRANSPORT_UDP_HPP -#define INCLUDED_UHD_TRANSPORT_UDP_HPP - -namespace uhd{ namespace transport{ - -class udp : boost::noncopyable{ -public: - typedef boost::shared_ptr sptr; - - /*! - * Make a new udp transport. - * The address will be resolved, it can be a host name or ipv4. - * The port will be resolved, it can be a port type or number. - * \param addr a string representing the destination address - * \param port a string representing the destination port - * \param bcast if true, enable the broadcast option on the socket - */ - static sptr make(const std::string &addr, const std::string &port, bool bcast = false); - - /*! - * Send a vector of buffer (like send_msg). - * Blocks until the data is sent. - * \param buffs a vector of asio buffers - * \return the number of bytes sent - */ - virtual size_t send(const std::vector &buffs) = 0; - - /*! - * Send a single buffer. - * Blocks until the data is sent. - * \param buff single asio buffer - * \return the number of bytes sent - */ - virtual size_t send(const boost::asio::const_buffer &buff) = 0; - - /*! - * Receive a buffer. Write into the memory provided. - * Returns empty when data is not available. - * \param buffs a vector of asio buffers - * \return the number of bytes received. - */ - virtual size_t recv(const std::vector &buffs) = 0; - - /*! - * Receive a buffer. Write into the memory provided. - * Returns empty when data is not available. - * \param buff a mutable buffer to receive into - * \return the number of bytes received. - */ - virtual size_t recv(const boost::asio::mutable_buffer &buff) = 0; -}; - -}} //namespace - -#endif /* INCLUDED_UHD_TRANSPORT_UDP_HPP */ diff --git a/host/include/uhd/transport/udp_simple.hpp b/host/include/uhd/transport/udp_simple.hpp new file mode 100644 index 000000000..8663128ec --- /dev/null +++ b/host/include/uhd/transport/udp_simple.hpp @@ -0,0 +1,79 @@ +// +// 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 + +#ifndef INCLUDED_UHD_TRANSPORT_UDP_SIMPLE_HPP +#define INCLUDED_UHD_TRANSPORT_UDP_SIMPLE_HPP + +namespace uhd{ namespace transport{ + +class udp_simple : boost::noncopyable{ +public: + typedef boost::shared_ptr sptr; + + /*! + * Make a new connected udp transport: + * This transport is for sending and receiving + * between this host and a single endpoint. + * The primary usage for this transport will be control transactions. + * The underlying implementation is simple and portable (not fast). + * + * The address will be resolved, it can be a host name or ipv4. + * The port will be resolved, it can be a port type or number. + * + * \param addr a string representing the destination address + * \param port a string representing the destination port + */ + static sptr make_connected(const std::string &addr, const std::string &port); + + /*! + * Make a new broadcasting udp transport: + * This transport can send udp broadcast datagrams + * and receive datagrams from multiple sources. + * The primary usage for this transport will be to discover devices. + * + * The address will be resolved, it can be a host name or ipv4. + * The port will be resolved, it can be a port type or number. + * + * \param addr a string representing the destination address + * \param port a string representing the destination port + */ + static sptr make_broadcast(const std::string &addr, const std::string &port); + + /*! + * Send a single buffer. + * Blocks until the data is sent. + * \param buff single asio buffer + * \return the number of bytes sent + */ + virtual size_t send(const boost::asio::const_buffer &buff) = 0; + + /*! + * Receive into the provided buffer. + * Returns empty when data is not available. + * \param buff a mutable buffer to receive into + * \return the number of bytes received. + */ + virtual size_t recv(const boost::asio::mutable_buffer &buff) = 0; +}; + +}} //namespace + +#endif /* INCLUDED_UHD_TRANSPORT_UDP_SIMPLE_HPP */ diff --git a/host/include/uhd/transport/udp_zero_copy.hpp b/host/include/uhd/transport/udp_zero_copy.hpp new file mode 100644 index 000000000..9c3505dd6 --- /dev/null +++ b/host/include/uhd/transport/udp_zero_copy.hpp @@ -0,0 +1,76 @@ +// +// 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 + +#ifndef INCLUDED_UHD_TRANSPORT_UDP_ZERO_COPY_HPP +#define INCLUDED_UHD_TRANSPORT_UDP_ZERO_COPY_HPP + +namespace uhd{ namespace transport{ + +/*! + * A zero copy udp transport provides an efficient way to handle data. + * by avoiding the extra copy when recv() is called on the socket. + * Rather, the zero copy transport gives the caller a memory reference. + * The caller informs the transport when it is finished with the reference. + * + * On linux systems, the zero copy transport can use a kernel packet ring. + * If no platform specific solution is available, make returns a boost asio + * implementation that wraps the functionality around a standard recv() call. + */ +class udp_zero_copy : boost::noncopyable{ +public: + typedef boost::shared_ptr sptr; + + /*! + * Make a new zero copy udp transport: + * This transport is for sending and receiving + * between this host and a single endpoint. + * The primary usage for this transport will be data transactions. + * The underlying implementation is fast and platform specific. + * + * The address will be resolved, it can be a host name or ipv4. + * The port will be resolved, it can be a port type or number. + * + * \param addr a string representing the destination address + * \param port a string representing the destination port + */ + static sptr make(const std::string &addr, const std::string &port); + + /*! + * Send a single buffer. + * Blocks until the data is sent. + * \param buff single asio buffer + * \return the number of bytes sent + */ + virtual size_t send(const boost::asio::const_buffer &buff) = 0; + + /*! + * Receive a buffer. + * The memory is managed by the implementation. + * Returns an empty buffer when data is not available. + * \return a smart buffer with memory and size + */ + virtual smart_buffer::sptr recv(void) = 0; +}; + +}} //namespace + +#endif /* INCLUDED_UHD_TRANSPORT_UDP_ZERO_COPY_HPP */ diff --git a/host/include/uhd/usrp/usrp2.hpp b/host/include/uhd/usrp/usrp2.hpp index da7ec595a..b13786546 100644 --- a/host/include/uhd/usrp/usrp2.hpp +++ b/host/include/uhd/usrp/usrp2.hpp @@ -29,6 +29,11 @@ class usrp2 : public device{ public: /*! * Discover usrp2 devices over the ethernet. + * + * Recommended key/value pairs for the device hint address: + * hint["addr"] = address, where address is a resolvable address + * or ip address, which may or may not be a broadcast address. + * * This static method will be called by the device::discover. * \param hint a device addr with the usrp2 address filled in * \return a vector of device addresses for all usrp2s found @@ -37,6 +42,11 @@ public: /*! * Make a usrp2 from a device address. + * + * Required key/value pairs for the device address: + * hint["addr"] = address, where address is a resolvable address + * or ip address, which must be the specific address of a usrp2. + * * \param addr the device address * \return a device sptr to a new usrp2 */ diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index 97f1ac52e..a52cd74a9 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -23,7 +23,7 @@ SET(libuhd_sources device_addr.cpp gain_handler.cpp wax.cpp - transport/udp.cpp + transport/udp_simple.cpp usrp/dboard/basic.cpp usrp/dboard_base.cpp usrp/dboard_id.cpp @@ -37,6 +37,13 @@ SET(libuhd_sources usrp/usrp2/usrp2_impl.cpp ) +######################################################################## +# Conditionally add the udp sources +######################################################################## +LIST(APPEND libuhd_sources + transport/udp_zero_copy_none.cpp +) + ######################################################################## # Conditionally add the usrp1e sources ######################################################################## diff --git a/host/lib/transport/udp.cpp b/host/lib/transport/udp.cpp deleted file mode 100644 index 878f71410..000000000 --- a/host/lib/transport/udp.cpp +++ /dev/null @@ -1,98 +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 -#include -#include - -/*********************************************************************** - * UDP implementation class - **********************************************************************/ -class udp_impl : public uhd::transport::udp{ -public: - //structors - udp_impl(const std::string &addr, const std::string &port, bool bcast); - ~udp_impl(void); - - //send/recv - size_t send(const std::vector &buffs); - size_t send(const boost::asio::const_buffer &buff); - size_t recv(const std::vector &buffs); - size_t recv(const boost::asio::mutable_buffer &buff); - -private: - boost::asio::ip::udp::socket *_socket; - boost::asio::ip::udp::endpoint _receiver_endpoint; - boost::asio::ip::udp::endpoint _sender_endpoint; - boost::asio::io_service _io_service; -}; - -/*********************************************************************** - * UDP public make function - **********************************************************************/ -uhd::transport::udp::sptr uhd::transport::udp::make( - const std::string &addr, - const std::string &port, - bool bcast -){ - return uhd::transport::udp::sptr(new udp_impl(addr, port, bcast)); -} - -/*********************************************************************** - * UDP implementation methods - **********************************************************************/ -udp_impl::udp_impl(const std::string &addr, const std::string &port, bool bcast){ - //std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl; - - // resolve the address - boost::asio::ip::udp::resolver resolver(_io_service); - boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), addr, port); - _receiver_endpoint = *resolver.resolve(query); - - // Create and open the socket - _socket = new boost::asio::ip::udp::socket(_io_service); - _socket->open(boost::asio::ip::udp::v4()); - - if (bcast){ - // Allow broadcasting - boost::asio::socket_base::broadcast option(true); - _socket->set_option(option); - } - -} - -udp_impl::~udp_impl(void){ - delete _socket; -} - -size_t udp_impl::send(const std::vector &buffs){ - return _socket->send_to(buffs, _receiver_endpoint); -} - -size_t udp_impl::send(const boost::asio::const_buffer &buff){ - return _socket->send_to(boost::asio::buffer(buff), _receiver_endpoint); -} - -size_t udp_impl::recv(const std::vector &buffs){ - if (_socket->available() == 0) return 0; - return _socket->receive_from(buffs, _sender_endpoint); -} - -size_t udp_impl::recv(const boost::asio::mutable_buffer &buff){ - if (_socket->available() == 0) return 0; - return _socket->receive_from(boost::asio::buffer(buff), _sender_endpoint); -} diff --git a/host/lib/transport/udp_simple.cpp b/host/lib/transport/udp_simple.cpp new file mode 100644 index 000000000..491cf59db --- /dev/null +++ b/host/lib/transport/udp_simple.cpp @@ -0,0 +1,133 @@ +// +// 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 + +using namespace uhd::transport; + +/*********************************************************************** + * UDP connected implementation class + **********************************************************************/ +class udp_connected_impl : public udp_simple{ +public: + //structors + udp_connected_impl(const std::string &addr, const std::string &port); + ~udp_connected_impl(void); + + //send/recv + size_t send(const boost::asio::const_buffer &buff); + size_t recv(const boost::asio::mutable_buffer &buff); + +private: + boost::asio::ip::udp::socket *_socket; + boost::asio::io_service _io_service; +}; + +udp_connected_impl::udp_connected_impl(const std::string &addr, const std::string &port){ + //std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl; + + // resolve the address + boost::asio::ip::udp::resolver resolver(_io_service); + 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 + _socket = new boost::asio::ip::udp::socket(_io_service); + _socket->open(boost::asio::ip::udp::v4()); + _socket->connect(receiver_endpoint); +} + +udp_connected_impl::~udp_connected_impl(void){ + delete _socket; +} + +size_t udp_connected_impl::send(const boost::asio::const_buffer &buff){ + return _socket->send(boost::asio::buffer(buff)); +} + +size_t udp_connected_impl::recv(const boost::asio::mutable_buffer &buff){ + if (_socket->available() == 0) return 0; + return _socket->receive(boost::asio::buffer(buff)); +} + +/*********************************************************************** + * UDP broadcast implementation class + **********************************************************************/ +class udp_broadcast_impl : public udp_simple{ +public: + //structors + udp_broadcast_impl(const std::string &addr, const std::string &port); + ~udp_broadcast_impl(void); + + //send/recv + size_t send(const boost::asio::const_buffer &buff); + size_t recv(const boost::asio::mutable_buffer &buff); + +private: + boost::asio::ip::udp::socket *_socket; + boost::asio::ip::udp::endpoint _receiver_endpoint; + boost::asio::io_service _io_service; +}; + +udp_broadcast_impl::udp_broadcast_impl(const std::string &addr, const std::string &port){ + //std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl; + + // resolve the address + boost::asio::ip::udp::resolver resolver(_io_service); + boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), addr, port); + _receiver_endpoint = *resolver.resolve(query); + + // Create and open the socket + _socket = new boost::asio::ip::udp::socket(_io_service); + _socket->open(boost::asio::ip::udp::v4()); + + // Allow broadcasting + boost::asio::socket_base::broadcast option(true); + _socket->set_option(option); + +} + +udp_broadcast_impl::~udp_broadcast_impl(void){ + delete _socket; +} + +size_t udp_broadcast_impl::send(const boost::asio::const_buffer &buff){ + return _socket->send_to(boost::asio::buffer(buff), _receiver_endpoint); +} + +size_t udp_broadcast_impl::recv(const boost::asio::mutable_buffer &buff){ + if (_socket->available() == 0) return 0; + boost::asio::ip::udp::endpoint sender_endpoint; + return _socket->receive_from(boost::asio::buffer(buff), sender_endpoint); +} + +/*********************************************************************** + * UDP public make functions + **********************************************************************/ +udp_simple::sptr udp_simple::make_connected( + const std::string &addr, const std::string &port +){ + return sptr(new udp_connected_impl(addr, port)); +} + +udp_simple::sptr udp_simple::make_broadcast( + const std::string &addr, const std::string &port +){ + return sptr(new udp_broadcast_impl(addr, port)); +} diff --git a/host/lib/transport/udp_zero_copy_none.cpp b/host/lib/transport/udp_zero_copy_none.cpp new file mode 100644 index 000000000..e95706d94 --- /dev/null +++ b/host/lib/transport/udp_zero_copy_none.cpp @@ -0,0 +1,117 @@ +// +// 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 + +using namespace uhd::transport; + +/*********************************************************************** + * Smart buffer implementation for udp zerocopy none + * + * This smart buffer implemention houses a const buffer. + * When the smart buffer is deleted, the buffer is freed. + * The memory in the const buffer is allocated with new [], + * and so the destructor frees the buffer with delete []. + **********************************************************************/ +class smart_buffer_impl : public smart_buffer{ +public: + smart_buffer_impl(const boost::asio::const_buffer &buff){ + _buff = buff; + } + + ~smart_buffer_impl(void){ + delete [] boost::asio::buffer_cast(_buff); + } + + const boost::asio::const_buffer &get(void) const{ + return _buff; + } + +private: + boost::asio::const_buffer _buff; +}; + +/*********************************************************************** + * UDP zero copy implementation class + * + * This is the portable zero copy implementation for systems + * where a faster, platform specific solution is not available. + * + * It uses boost asio udp sockets and the standard recv() class, + * and in-fact, is not actually doing a zero-copy implementation. + **********************************************************************/ +class udp_zero_copy_impl : public udp_zero_copy{ +public: + //structors + udp_zero_copy_impl(const std::string &addr, const std::string &port); + ~udp_zero_copy_impl(void); + + //send/recv + size_t send(const boost::asio::const_buffer &buff); + smart_buffer::sptr recv(void); + +private: + boost::asio::ip::udp::socket *_socket; + boost::asio::io_service _io_service; +}; + +udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::string &port){ + //std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl; + + // resolve the address + boost::asio::ip::udp::resolver resolver(_io_service); + 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 + _socket = new boost::asio::ip::udp::socket(_io_service); + _socket->open(boost::asio::ip::udp::v4()); + _socket->connect(receiver_endpoint); +} + +udp_zero_copy_impl::~udp_zero_copy_impl(void){ + delete _socket; +} + +size_t udp_zero_copy_impl::send(const boost::asio::const_buffer &buff){ + return _socket->send(boost::asio::buffer(buff)); +} + +smart_buffer::sptr udp_zero_copy_impl::recv(void){ + size_t available = _socket->available(); + + //allocate memory and create buffer + uint32_t *buff_mem = new uint32_t[available/sizeof(uint32_t)]; + boost::asio::mutable_buffer buff(buff_mem, available); + + //receive only if data is available + if (available > 0){ + _socket->receive(boost::asio::buffer(buff)); + } + + //create a new smart buffer to house the data + return smart_buffer::sptr(new smart_buffer_impl(buff)); +} + +/*********************************************************************** + * UDP zero copy make function + **********************************************************************/ +udp_zero_copy::sptr udp_zero_copy::make( + const std::string &addr, const std::string &port +){ + return sptr(new udp_zero_copy_impl(addr, port)); +} diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 0ca2409c3..6969e0a89 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -36,12 +36,12 @@ static const float floats_per_short = 1.0/shorts_per_float; * Helper Functions **********************************************************************/ void usrp2_impl::io_init(void){ - //initially empty spillover buffer - _splillover_buff = asio::buffer(_spillover_mem, 0); + //initially empty copy buffer + _rx_copy_buff = asio::buffer("", 0); //send a small data packet so the usrp2 knows the udp source port uint32_t zero_data = 0; - _data_transport->send(boost::asio::buffer(&zero_data, sizeof(zero_data))); + _data_transport->send(asio::buffer(&zero_data, sizeof(zero_data))); } #define unrolled_loop(__i, __len, __inst) {\ @@ -57,6 +57,13 @@ void usrp2_impl::io_init(void){ } \ } +// set a boolean flag that indicates the endianess +#ifdef HAVE_BIG_ENDIAN +static const bool is_big_endian = true; +#else +static const bool is_big_endian = false; +#endif + static inline void host_floats_to_usrp2_items( uint32_t *usrp2_items, const fc32_t *host_floats, @@ -87,9 +94,12 @@ static inline void host_items_to_usrp2_items( const uint32_t *host_items, size_t num_samps ){ - unrolled_loop(i, num_samps, - usrp2_items[i] = htonl(host_items[i]) - ); + if (is_big_endian){ + std::memcpy(usrp2_items, host_items, num_samps*sizeof(uint32_t)); + } + else{ + unrolled_loop(i, num_samps, usrp2_items[i] = htonl(host_items[i])); + } } static inline void usrp2_items_to_host_items( @@ -97,20 +107,22 @@ static inline void usrp2_items_to_host_items( const uint32_t *usrp2_items, size_t num_samps ){ - unrolled_loop(i, num_samps, - host_items[i] = ntohl(usrp2_items[i]) - ); + if (is_big_endian){ + std::memcpy(host_items, usrp2_items, num_samps*sizeof(uint32_t)); + } + else{ + unrolled_loop(i, num_samps, host_items[i] = ntohl(usrp2_items[i])); + } } /*********************************************************************** * Send Raw Data **********************************************************************/ -size_t usrp2_impl::send_raw( - const boost::asio::const_buffer &buff, - const uhd::metadata_t &metadata -){ - std::vector buffs(2); - uint32_t vrt_hdr[7]; //max size +size_t usrp2_impl::send_raw(const uhd::metadata_t &metadata){ + size_t num_items = asio::buffer_size(_tx_copy_buff)/sizeof(uint32_t); + const uint32_t *items = asio::buffer_cast(_tx_copy_buff); + + uint32_t vrt_hdr[_tx_vrt_max_offset_words32]; uint32_t vrt_hdr_flags = 0; size_t num_vrt_hdr_words = 1; @@ -131,60 +143,30 @@ size_t usrp2_impl::send_raw( //fill in complete header word vrt_hdr[0] = htonl(vrt_hdr_flags | ((_tx_stream_id_to_packet_seq[metadata.stream_id]++ & 0xf) << 16) | - ((num_vrt_hdr_words + asio::buffer_size(buff)/sizeof(uint32_t)) & 0xffff) + ((num_vrt_hdr_words + num_items) & 0xffff) ); - //load the buffer vector - size_t vrt_hdr_size = num_vrt_hdr_words*sizeof(uint32_t); - buffs[0] = asio::buffer(&vrt_hdr, vrt_hdr_size); - buffs[1] = buff; + //copy in the vrt header (yes we left space) + std::memcpy(((uint32_t *)items) - num_vrt_hdr_words, vrt_hdr, num_vrt_hdr_words); + asio::const_buffer buff(items - num_vrt_hdr_words, (num_vrt_hdr_words + num_items)*sizeof(uint32_t)); //send and return number of samples - return (_data_transport->send(buffs) - vrt_hdr_size)/sizeof(sc16_t); + return (_data_transport->send(buff) - num_vrt_hdr_words*sizeof(uint32_t))/sizeof(sc16_t); } /*********************************************************************** * Receive Raw Data **********************************************************************/ -size_t usrp2_impl::recv_raw( - const boost::asio::mutable_buffer &buff, - uhd::metadata_t &metadata -){ - metadata = metadata_t(); //clear metadata - - //handle the case where there is spillover - if (asio::buffer_size(_splillover_buff) != 0){ - size_t bytes_to_copy = std::min( - asio::buffer_size(_splillover_buff), - asio::buffer_size(buff) - ); - std::memcpy( - asio::buffer_cast(buff), - asio::buffer_cast(_splillover_buff), - bytes_to_copy - ); - _splillover_buff = asio::buffer( - asio::buffer_cast(_splillover_buff)+bytes_to_copy, - asio::buffer_size(_splillover_buff)-bytes_to_copy - ); - //std::cout << boost::format("Copied spillover %d samples") % (bytes_to_copy/sizeof(sc16_t)) << std::endl; - return bytes_to_copy/sizeof(sc16_t); - } - - //load the buffer vector - std::vector buffs(3); - uint32_t vrt_hdr[USRP2_HOST_RX_VRT_HEADER_WORDS32]; - buffs[0] = asio::buffer(vrt_hdr, sizeof(vrt_hdr)); - buffs[1] = buff; - buffs[2] = asio::buffer(_spillover_mem, _mtu); +void usrp2_impl::recv_raw(uhd::metadata_t &metadata){ + //do a receive + _rx_smart_buff = _data_transport->recv(); - //receive into the buffers - size_t bytes_recvd = _data_transport->recv(buffs); - - //failure case - if (bytes_recvd < sizeof(vrt_hdr)) return 0; + //////////////////////////////////////////////////////////////////// + // !!!! FIXME this is very flawed, use a proper vrt unpacker !!!!!!! + //////////////////////////////////////////////////////////////////// //unpack the vrt header + const uint32_t *vrt_hdr = asio::buffer_cast(_rx_smart_buff->get()); metadata = uhd::metadata_t(); uint32_t vrt_header = ntohl(vrt_hdr[0]); metadata.has_stream_id = true; @@ -202,13 +184,12 @@ size_t usrp2_impl::recv_raw( size_t num_words = (vrt_header & 0xffff) - USRP2_HOST_RX_VRT_HEADER_WORDS32 - USRP2_HOST_RX_VRT_TRAILER_WORDS32; - size_t num_bytes = num_words*sizeof(uint32_t); - - //handle the case where spillover memory was used - size_t spillover_size = num_bytes - std::min(num_bytes, asio::buffer_size(buff)); - _splillover_buff = asio::buffer(_spillover_mem, spillover_size); - return (num_bytes - spillover_size)/sizeof(sc16_t); + //setup the rx buffer to point to the data + _rx_copy_buff = boost::asio::buffer( + vrt_hdr + USRP2_HOST_RX_VRT_HEADER_WORDS32, + num_words*sizeof(uint32_t) + ); } /*********************************************************************** @@ -219,37 +200,26 @@ size_t usrp2_impl::send( const uhd::metadata_t &metadata, const std::string &type ){ - if (type == "32fc"){ - size_t num_samps = asio::buffer_size(buff)/sizeof(fc32_t); - boost::asio::mutable_buffer raw_buff(_tmp_send_mem, num_samps*sizeof(sc16_t)); + uint32_t *items = _tx_mem + _tx_vrt_max_offset_words32; //offset for data + size_t num_samps = _max_samples_per_packet; - host_floats_to_usrp2_items( - asio::buffer_cast(raw_buff), - asio::buffer_cast(buff), - num_samps - ); - - return send_raw(raw_buff, metadata); + //calculate the number of samples to be copied + //and copy the samples into the send buffer + if (type == "32fc"){ + num_samps = std::min(asio::buffer_size(buff)/sizeof(fc32_t), num_samps); + host_floats_to_usrp2_items(items, asio::buffer_cast(buff), num_samps); } - - if (type == "16sc"){ - #ifdef HAVE_BIG_ENDIAN - return send_raw(buff, metadata); - #else - size_t num_samps = asio::buffer_size(buff)/sizeof(sc16_t); - boost::asio::mutable_buffer raw_buff(_tmp_send_mem, num_samps*sizeof(sc16_t)); - - host_items_to_usrp2_items( - asio::buffer_cast(raw_buff), - asio::buffer_cast(buff), - num_samps - ); - - return send_raw(raw_buff, metadata); - #endif + else if (type == "16sc"){ + num_samps = std::min(asio::buffer_size(buff)/sizeof(sc16_t), num_samps); + host_items_to_usrp2_items(items, asio::buffer_cast(buff), num_samps); + } + else{ + throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%s\"") % type)); } - throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%s\"") % type)); + //send the samples (this line seems silly, will be better with vrt lib) + _tx_copy_buff = asio::buffer(items, num_samps*sizeof(uint32_t)); + return send_raw(metadata); //return num_samps; } /*********************************************************************** @@ -260,39 +230,31 @@ size_t usrp2_impl::recv( uhd::metadata_t &metadata, const std::string &type ){ - if (type == "32fc"){ - size_t num_samps = asio::buffer_size(buff)/sizeof(fc32_t); - boost::asio::mutable_buffer raw_buff(_tmp_recv_mem, num_samps*sizeof(sc16_t)); - - num_samps = recv_raw(raw_buff, metadata); + //perform a receive if no rx data is waiting to be copied + if (asio::buffer_size(_rx_copy_buff) == 0) recv_raw(metadata); + //TODO otherwise flag the metadata to show that is is a fragment - usrp2_items_to_host_floats( - asio::buffer_cast(buff), - asio::buffer_cast(raw_buff), - num_samps - ); + //extract the number of samples available to copy + //and a pointer into the usrp2 received items memory + size_t num_samps = asio::buffer_size(_rx_copy_buff)/sizeof(uint32_t); + const uint32_t *items = asio::buffer_cast(_rx_copy_buff); - return num_samps; + //calculate the number of samples to be copied + //and copy the samples from the recv buffer + if (type == "32fc"){ + num_samps = std::min(asio::buffer_size(buff)/sizeof(fc32_t), num_samps); + usrp2_items_to_host_floats(asio::buffer_cast(buff), items, num_samps); } - - if (type == "16sc"){ - #ifdef HAVE_BIG_ENDIAN - return recv_raw(buff, metadata); - #else - size_t num_samps = asio::buffer_size(buff)/sizeof(sc16_t); - boost::asio::mutable_buffer raw_buff(_tmp_recv_mem, num_samps*sizeof(sc16_t)); - - num_samps = recv_raw(raw_buff, metadata); - - usrp2_items_to_host_items( - asio::buffer_cast(buff), - asio::buffer_cast(raw_buff), - num_samps - ); - - return num_samps; - #endif + else if (type == "16sc"){ + num_samps = std::min(asio::buffer_size(buff)/sizeof(sc16_t), num_samps); + usrp2_items_to_host_items(asio::buffer_cast(buff), items, num_samps); + } + else{ + throw std::runtime_error(str(boost::format("usrp2 recv: cannot handle type \"%s\"") % type)); } - throw std::runtime_error(str(boost::format("usrp2 recv: cannot handle type \"%s\"") % type)); + //update the rx copy buffer to reflect the bytes copied + _rx_copy_buff = asio::buffer(items + num_samps, num_samps*sizeof(uint32_t)); + + return num_samps; } diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 700f94ae1..51082df15 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -23,6 +23,7 @@ using namespace uhd; using namespace uhd::usrp; +using namespace uhd::transport; /*********************************************************************** * Discovery over the udp transport @@ -33,8 +34,9 @@ uhd::device_addrs_t usrp2::discover(const device_addr_t &hint){ //create a udp transport to communicate //TODO if an addr is not provided, search all interfaces? std::string ctrl_port = boost::lexical_cast(USRP2_UDP_CTRL_PORT); - transport::udp::sptr udp_transport = \ - transport::udp::make(hint["addr"], ctrl_port, true); + udp_simple::sptr udp_transport = udp_simple::make_broadcast( + hint["addr"], ctrl_port + ); //send a hello control packet usrp2_ctrl_data_t ctrl_data_out; @@ -76,16 +78,18 @@ uhd::device_addrs_t usrp2::discover(const device_addr_t &hint){ /*********************************************************************** * Make **********************************************************************/ -#define num2str(num) (boost::lexical_cast(num)) +template std::string num2str(T num){ + return boost::lexical_cast(num); +} device::sptr usrp2::make(const device_addr_t &device_addr){ //create a control transport - transport::udp::sptr ctrl_transport = transport::udp::make( + udp_simple::sptr ctrl_transport = udp_simple::make_connected( device_addr["addr"], num2str(USRP2_UDP_CTRL_PORT) ); //create a data transport - transport::udp::sptr data_transport = transport::udp::make( + udp_zero_copy::sptr data_transport = udp_zero_copy::make( device_addr["addr"], num2str(USRP2_UDP_DATA_PORT) ); @@ -99,8 +103,8 @@ device::sptr usrp2::make(const device_addr_t &device_addr){ * Structors **********************************************************************/ usrp2_impl::usrp2_impl( - transport::udp::sptr ctrl_transport, - transport::udp::sptr data_transport + udp_simple::sptr ctrl_transport, + udp_zero_copy::sptr data_transport ){ _ctrl_transport = ctrl_transport; _data_transport = data_transport; diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 037aed477..a58bf8471 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -22,7 +22,8 @@ #include #include #include -#include +#include +#include #include #include "fw_common.h" @@ -81,8 +82,8 @@ public: * \param data_transport the udp transport for data */ usrp2_impl( - uhd::transport::udp::sptr ctrl_transport, - uhd::transport::udp::sptr data_transport + uhd::transport::udp_simple::sptr ctrl_transport, + uhd::transport::udp_zero_copy::sptr data_transport ); ~usrp2_impl(void); @@ -103,8 +104,8 @@ public: private: //the raw io interface (samples are in the usrp2 native format) - size_t send_raw(const boost::asio::const_buffer &, const uhd::metadata_t &); - size_t recv_raw(const boost::asio::mutable_buffer &, uhd::metadata_t &); + size_t send_raw(const uhd::metadata_t &); + void recv_raw(uhd::metadata_t &); uhd::dict _tx_stream_id_to_packet_seq; uhd::dict _rx_stream_id_to_packet_seq; static const size_t _mtu = 1500; //FIXME we have no idea @@ -114,15 +115,16 @@ private: USRP2_HOST_RX_VRT_TRAILER_WORDS32 - ((2 + 14 + 20 + 8)/sizeof(uint32_t)) //size of headers (pad, eth, ip, udp) ; - uint32_t _tmp_send_mem[_mtu/sizeof(uint32_t)]; - uint32_t _tmp_recv_mem[_mtu/sizeof(uint32_t)]; - uint32_t _spillover_mem[_mtu/sizeof(uint32_t)]; - boost::asio::mutable_buffer _splillover_buff; + static const size_t _tx_vrt_max_offset_words32 = 7; //TODO move to future vrt lib + uint32_t _tx_mem[_mtu/sizeof(uint32_t)]; + boost::asio::const_buffer _tx_copy_buff; + uhd::transport::smart_buffer::sptr _rx_smart_buff; + boost::asio::const_buffer _rx_copy_buff; void io_init(void); //udp transports for control and data - uhd::transport::udp::sptr _ctrl_transport; - uhd::transport::udp::sptr _data_transport; + uhd::transport::udp_simple::sptr _ctrl_transport; + uhd::transport::udp_zero_copy::sptr _data_transport; //private vars for dealing with send/recv control uint32_t _ctrl_seq_num; -- cgit v1.2.3 From 8e8221dc380fb275a17dcd0abbfaea108f44505f Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 2 Mar 2010 23:56:19 -0800 Subject: Added a vrt library to pack and unpack from metadata. Added a vrt test app that packs and unpacks the data. --- host/include/uhd/transport/CMakeLists.txt | 1 + host/include/uhd/transport/vrt.hpp | 66 +++++++++++++++++++ host/lib/CMakeLists.txt | 1 + host/lib/transport/vrt.cpp | 104 ++++++++++++++++++++++++++++++ host/test/CMakeLists.txt | 1 + host/test/vrt_test.cpp | 97 ++++++++++++++++++++++++++++ 6 files changed, 270 insertions(+) create mode 100644 host/include/uhd/transport/vrt.hpp create mode 100644 host/lib/transport/vrt.cpp create mode 100644 host/test/vrt_test.cpp diff --git a/host/include/uhd/transport/CMakeLists.txt b/host/include/uhd/transport/CMakeLists.txt index ba8b33cc5..7f5db2128 100644 --- a/host/include/uhd/transport/CMakeLists.txt +++ b/host/include/uhd/transport/CMakeLists.txt @@ -20,5 +20,6 @@ INSTALL(FILES smart_buffer.hpp udp_simple.hpp udp_zero_copy.hpp + vrt.hpp DESTINATION ${HEADER_DIR}/uhd/transport ) diff --git a/host/include/uhd/transport/vrt.hpp b/host/include/uhd/transport/vrt.hpp new file mode 100644 index 000000000..b56da4077 --- /dev/null +++ b/host/include/uhd/transport/vrt.hpp @@ -0,0 +1,66 @@ +// +// 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 + +#ifndef INCLUDED_UHD_TRANSPORT_VRT_HPP +#define INCLUDED_UHD_TRANSPORT_VRT_HPP + +namespace uhd{ namespace transport{ + +namespace vrt{ + + static const size_t max_header_words32 = 7; + + /*! + * Pack a vrt header from metadata. + * \param metadata the tx metadata with flags and timestamps + * \param header_buff memory to write the packed vrt header + * \param num_header_words32 number of words in the vrt header + * \param num_payload_words32 the length of the payload + * \param packet_count the packet count sequence number + */ + void pack( + const metadata_t &metadata, //input + uint32_t *header_buff, //output + size_t &num_header_words32, //output + size_t num_payload_words32, //input + size_t packet_count //input + ); + + /*! + * Unpack a vrt header to metadata. + * \param metadata the rx metadata with flags and timestamps + * \param header_buff memory to read the packed vrt header + * \param num_header_words32 number of words in the vrt header + * \param num_payload_words32 the length of the payload + * \param packet_count the packet count sequence number + */ + void unpack( + metadata_t &metadata, //output + const uint32_t *header_buff, //input + size_t &num_header_words32, //output + size_t &num_payload_words32, //output + size_t &packet_count //output + ); + +} //namespace vrt + +}} //namespace + +#endif /* INCLUDED_UHD_TRANSPORT_VRT_HPP */ diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index a52cd74a9..390349906 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -24,6 +24,7 @@ SET(libuhd_sources gain_handler.cpp wax.cpp transport/udp_simple.cpp + transport/vrt.cpp usrp/dboard/basic.cpp usrp/dboard_base.cpp usrp/dboard_id.cpp diff --git a/host/lib/transport/vrt.cpp b/host/lib/transport/vrt.cpp new file mode 100644 index 000000000..40b26d31f --- /dev/null +++ b/host/lib/transport/vrt.cpp @@ -0,0 +1,104 @@ +// +// 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 + +using namespace uhd::transport; + +void vrt::pack( + const metadata_t &metadata, //input + uint32_t *header_buff, //output + size_t &num_header_words32, //output + size_t num_payload_words32, //input + size_t packet_count //input +){ + uint32_t vrt_hdr_flags = 0; + num_header_words32 = 1; + + //load the vrt header and flags + if(metadata.has_stream_id){ + vrt_hdr_flags |= (0x1 << 28); //IF Data packet with Stream Identifier + header_buff[num_header_words32++] = htonl(metadata.stream_id); + } + + if(metadata.has_time_spec){ + vrt_hdr_flags |= (0x3 << 22) | (0x1 << 20); //TSI: Other, TSF: Sample Count Timestamp + header_buff[num_header_words32++] = htonl(metadata.time_spec.secs); + header_buff[num_header_words32++] = htonl(metadata.time_spec.ticks); + header_buff[num_header_words32++] = 0; //unused part of fractional seconds + } + + vrt_hdr_flags |= (metadata.start_of_burst)? (0x1 << 25) : 0; + vrt_hdr_flags |= (metadata.end_of_burst)? (0x1 << 24) : 0; + + //fill in complete header word + header_buff[0] = htonl(vrt_hdr_flags | + ((packet_count & 0xf) << 16) | + ((num_header_words32 + num_payload_words32) & 0xffff) + ); +} + +void vrt::unpack( + metadata_t &metadata, //output + const uint32_t *header_buff, //input + size_t &num_header_words32, //output + size_t &num_payload_words32, //output + size_t &packet_count //output +){ + //clear the metadata + metadata = metadata_t(); + + //extract vrt header + uint32_t vrt_hdr_word = ntohl(header_buff[0]); + size_t packet_words32 = vrt_hdr_word & 0xffff; + packet_count = (vrt_hdr_word >> 16) & 0xf; + + //failure cases + if (packet_words32 == 0) //FIXME check the packet length before we continue + throw std::runtime_error("bad vrt header"); + if (vrt_hdr_word & (0x7 << 29)) + throw std::runtime_error("unsupported vrt packet type"); + + //parse the header flags + num_header_words32 = 1; + + if (vrt_hdr_word & (0x1 << 28)){ //stream id + metadata.has_stream_id = true; + metadata.stream_id = ntohl(header_buff[num_header_words32++]); + } + + if (vrt_hdr_word & (0x1 << 27)){ //class id (we dont use) + num_header_words32 += 2; + } + + if (vrt_hdr_word & (0x3 << 22)){ //integer time + metadata.has_time_spec = true; + metadata.time_spec.secs = ntohl(header_buff[num_header_words32++]); + } + + if (vrt_hdr_word & (0x3 << 20)){ //fractional time + metadata.has_time_spec = true; + metadata.time_spec.ticks = ntohl(header_buff[num_header_words32++]); + num_header_words32++; //unused part of fractional seconds + } + + size_t num_trailer_words32 = (vrt_hdr_word & (0x1 << 26))? 1 : 0; + + num_payload_words32 = packet_words32 - num_header_words32 - num_trailer_words32; +} diff --git a/host/test/CMakeLists.txt b/host/test/CMakeLists.txt index 234b6f92c..b1d5924c7 100644 --- a/host/test/CMakeLists.txt +++ b/host/test/CMakeLists.txt @@ -20,6 +20,7 @@ ADD_EXECUTABLE(main_test main_test.cpp addr_test.cpp gain_handler_test.cpp + vrt_test.cpp wax_test.cpp ) diff --git a/host/test/vrt_test.cpp b/host/test/vrt_test.cpp new file mode 100644 index 000000000..9b2d43430 --- /dev/null +++ b/host/test/vrt_test.cpp @@ -0,0 +1,97 @@ +// +// 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 + +using namespace uhd::transport; + +static void pack_and_unpack( + const uhd::metadata_t &metadata, + size_t num_payload_words32, + size_t packet_count +){ + uint32_t header_buff[vrt::max_header_words32]; + size_t num_header_words32; + + //pack metadata into a vrt header + vrt::pack( + metadata, //input + header_buff, //output + num_header_words32, //output + num_payload_words32, //input + packet_count //input + ); + + uhd::metadata_t metadata_out; + size_t num_header_words32_out; + size_t num_payload_words32_out; + size_t packet_count_out; + + //unpack the vrt header back into metadata + vrt::unpack( + metadata_out, //output + header_buff, //input + num_header_words32_out, //output + num_payload_words32_out, //output + packet_count_out //output + ); + + //check the the unpacked metadata is the same + BOOST_CHECK_EQUAL(packet_count, packet_count_out); + BOOST_CHECK_EQUAL(num_header_words32, num_header_words32_out); + BOOST_CHECK_EQUAL(num_payload_words32, num_payload_words32_out); + BOOST_CHECK_EQUAL(metadata.has_stream_id, metadata_out.has_stream_id); + if (metadata.has_stream_id and metadata_out.has_stream_id){ + BOOST_CHECK_EQUAL(metadata.stream_id, metadata_out.stream_id); + } + BOOST_CHECK_EQUAL(metadata.has_time_spec, metadata_out.has_time_spec); + if (metadata.has_time_spec and metadata_out.has_time_spec){ + BOOST_CHECK_EQUAL(metadata.time_spec.secs, metadata_out.time_spec.secs); + BOOST_CHECK_EQUAL(metadata.time_spec.ticks, metadata_out.time_spec.ticks); + } +} + +BOOST_AUTO_TEST_CASE(test_with_none){ + uhd::metadata_t metadata; + pack_and_unpack(metadata, 300, 1); +} + +BOOST_AUTO_TEST_CASE(test_with_sid){ + uhd::metadata_t metadata; + metadata.has_stream_id = true; + metadata.stream_id = 6; + pack_and_unpack(metadata, 400, 2); +} + +BOOST_AUTO_TEST_CASE(test_with_time_spec){ + uhd::metadata_t metadata; + metadata.has_time_spec = true; + metadata.time_spec.secs = 7; + metadata.time_spec.ticks = 2000; + pack_and_unpack(metadata, 500, 3); +} + +BOOST_AUTO_TEST_CASE(test_with_sid_and_time_spec){ + uhd::metadata_t metadata; + metadata.has_stream_id = true; + metadata.stream_id = 2; + metadata.has_time_spec = true; + metadata.time_spec.secs = 5; + metadata.time_spec.ticks = 1000; + pack_and_unpack(metadata, 600, 4); +} -- cgit v1.2.3 From bb8417526c14bd49192c159cbdc52f5ea0063784 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 3 Mar 2010 01:19:00 -0800 Subject: Making use of vrt lib in the usrp2 io_impl. Added a packet size param to the vrt pack and unpack. --- host/apps/discover_usrps.cpp | 1 + host/include/uhd/transport/vrt.hpp | 4 ++ host/lib/transport/vrt.cpp | 10 +++- host/lib/usrp/usrp2/dsp_impl.cpp | 2 +- host/lib/usrp/usrp2/io_impl.cpp | 115 ++++++++++++++++--------------------- host/lib/usrp/usrp2/usrp2_impl.cpp | 4 +- host/lib/usrp/usrp2/usrp2_impl.hpp | 17 +++--- host/test/vrt_test.cpp | 3 + 8 files changed, 76 insertions(+), 80 deletions(-) diff --git a/host/apps/discover_usrps.cpp b/host/apps/discover_usrps.cpp index 20ac1f9ed..448095726 100644 --- a/host/apps/discover_usrps.cpp +++ b/host/apps/discover_usrps.cpp @@ -63,6 +63,7 @@ int main(int argc, char *argv[]){ std::cout << "-- USRP Device " << i << std::endl; std::cout << "--------------------------------------------------" << std::endl; std::cout << device_addrs[i] << std::endl << std::endl; + //uhd::device::make(device_addrs[i]); //test make } return 0; diff --git a/host/include/uhd/transport/vrt.hpp b/host/include/uhd/transport/vrt.hpp index b56da4077..2fb90a497 100644 --- a/host/include/uhd/transport/vrt.hpp +++ b/host/include/uhd/transport/vrt.hpp @@ -33,6 +33,7 @@ namespace vrt{ * \param header_buff memory to write the packed vrt header * \param num_header_words32 number of words in the vrt header * \param num_payload_words32 the length of the payload + * \param num_packet_words32 the length of the packet * \param packet_count the packet count sequence number */ void pack( @@ -40,6 +41,7 @@ namespace vrt{ uint32_t *header_buff, //output size_t &num_header_words32, //output size_t num_payload_words32, //input + size_t &num_packet_words32, //output size_t packet_count //input ); @@ -49,6 +51,7 @@ namespace vrt{ * \param header_buff memory to read the packed vrt header * \param num_header_words32 number of words in the vrt header * \param num_payload_words32 the length of the payload + * \param num_packet_words32 the length of the packet * \param packet_count the packet count sequence number */ void unpack( @@ -56,6 +59,7 @@ namespace vrt{ const uint32_t *header_buff, //input size_t &num_header_words32, //output size_t &num_payload_words32, //output + size_t num_packet_words32, //input size_t &packet_count //output ); diff --git a/host/lib/transport/vrt.cpp b/host/lib/transport/vrt.cpp index 40b26d31f..19bfc1d19 100644 --- a/host/lib/transport/vrt.cpp +++ b/host/lib/transport/vrt.cpp @@ -26,6 +26,7 @@ void vrt::pack( uint32_t *header_buff, //output size_t &num_header_words32, //output size_t num_payload_words32, //input + size_t &num_packet_words32, //output size_t packet_count //input ){ uint32_t vrt_hdr_flags = 0; @@ -47,10 +48,12 @@ void vrt::pack( vrt_hdr_flags |= (metadata.start_of_burst)? (0x1 << 25) : 0; vrt_hdr_flags |= (metadata.end_of_burst)? (0x1 << 24) : 0; + num_packet_words32 = num_header_words32 + num_payload_words32; + //fill in complete header word header_buff[0] = htonl(vrt_hdr_flags | ((packet_count & 0xf) << 16) | - ((num_header_words32 + num_payload_words32) & 0xffff) + (num_packet_words32 & 0xffff) ); } @@ -59,6 +62,7 @@ void vrt::unpack( const uint32_t *header_buff, //input size_t &num_header_words32, //output size_t &num_payload_words32, //output + size_t num_packet_words32, //input size_t &packet_count //output ){ //clear the metadata @@ -70,8 +74,8 @@ void vrt::unpack( packet_count = (vrt_hdr_word >> 16) & 0xf; //failure cases - if (packet_words32 == 0) //FIXME check the packet length before we continue - throw std::runtime_error("bad vrt header"); + if (packet_words32 == 0 or num_packet_words32 < packet_words32) + throw std::runtime_error("bad vrt header or packet fragment"); if (vrt_hdr_word & (0x7 << 29)) throw std::runtime_error("unsupported vrt packet type"); diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index 8fdfd685f..a32f68872 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -82,7 +82,7 @@ void usrp2_impl::update_ddc_enabled(void){ out_data.data.streaming.enabled = (_ddc_enabled)? 1 : 0; out_data.data.streaming.secs = htonl(_ddc_stream_at.secs); out_data.data.streaming.ticks = htonl(_ddc_stream_at.ticks); - out_data.data.streaming.samples = htonl(_max_samples_per_packet); + out_data.data.streaming.samples = htonl(_max_rx_samples_per_packet); //send and recv usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 6969e0a89..9299bb04a 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -21,6 +21,7 @@ using namespace uhd; using namespace uhd::usrp; +using namespace uhd::transport; namespace asio = boost::asio; /*********************************************************************** @@ -115,45 +116,6 @@ static inline void usrp2_items_to_host_items( } } -/*********************************************************************** - * Send Raw Data - **********************************************************************/ -size_t usrp2_impl::send_raw(const uhd::metadata_t &metadata){ - size_t num_items = asio::buffer_size(_tx_copy_buff)/sizeof(uint32_t); - const uint32_t *items = asio::buffer_cast(_tx_copy_buff); - - uint32_t vrt_hdr[_tx_vrt_max_offset_words32]; - uint32_t vrt_hdr_flags = 0; - size_t num_vrt_hdr_words = 1; - - //load the vrt header and flags - if(metadata.has_stream_id){ - vrt_hdr_flags |= (0x1 << 28); //IF Data packet with Stream Identifier - vrt_hdr[num_vrt_hdr_words++] = htonl(metadata.stream_id); - } - if(metadata.has_time_spec){ - vrt_hdr_flags |= (0x3 << 22) | (0x1 << 20); //TSI: Other, TSF: Sample Count Timestamp - vrt_hdr[num_vrt_hdr_words++] = htonl(metadata.time_spec.secs); - vrt_hdr[num_vrt_hdr_words++] = htonl(metadata.time_spec.ticks); - vrt_hdr[num_vrt_hdr_words++] = 0; //unused part of fractional seconds - } - vrt_hdr_flags |= (metadata.start_of_burst)? (0x1 << 25) : 0; - vrt_hdr_flags |= (metadata.end_of_burst)? (0x1 << 24) : 0; - - //fill in complete header word - vrt_hdr[0] = htonl(vrt_hdr_flags | - ((_tx_stream_id_to_packet_seq[metadata.stream_id]++ & 0xf) << 16) | - ((num_vrt_hdr_words + num_items) & 0xffff) - ); - - //copy in the vrt header (yes we left space) - std::memcpy(((uint32_t *)items) - num_vrt_hdr_words, vrt_hdr, num_vrt_hdr_words); - asio::const_buffer buff(items - num_vrt_hdr_words, (num_vrt_hdr_words + num_items)*sizeof(uint32_t)); - - //send and return number of samples - return (_data_transport->send(buff) - num_vrt_hdr_words*sizeof(uint32_t))/sizeof(sc16_t); -} - /*********************************************************************** * Receive Raw Data **********************************************************************/ @@ -161,34 +123,37 @@ void usrp2_impl::recv_raw(uhd::metadata_t &metadata){ //do a receive _rx_smart_buff = _data_transport->recv(); - //////////////////////////////////////////////////////////////////// - // !!!! FIXME this is very flawed, use a proper vrt unpacker !!!!!!! - //////////////////////////////////////////////////////////////////// - //unpack the vrt header const uint32_t *vrt_hdr = asio::buffer_cast(_rx_smart_buff->get()); - metadata = uhd::metadata_t(); - uint32_t vrt_header = ntohl(vrt_hdr[0]); - metadata.has_stream_id = true; - metadata.stream_id = ntohl(vrt_hdr[1]); - metadata.has_time_spec = true; - metadata.time_spec.secs = ntohl(vrt_hdr[2]); - metadata.time_spec.ticks = ntohl(vrt_hdr[3]); - - size_t my_seq = (vrt_header >> 16) & 0xf; - //std::cout << "seq " << my_seq << std::endl; - if (my_seq != ((_rx_stream_id_to_packet_seq[metadata.stream_id]+1) & 0xf)) std::cout << "bad seq " << my_seq << std::endl; - _rx_stream_id_to_packet_seq[metadata.stream_id] = my_seq; + size_t num_packet_words32 = asio::buffer_size(_rx_smart_buff->get())/sizeof(uint32_t); + size_t num_header_words32_out; + size_t num_payload_words32_out; + size_t 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 + ); + }catch(const std::exception &e){ + std::cerr << "bad vrt header: " << e.what() << std::endl; + _rx_copy_buff = boost::asio::buffer("", 0); + } - //extract the number of bytes received - size_t num_words = (vrt_header & 0xffff) - - USRP2_HOST_RX_VRT_HEADER_WORDS32 - - USRP2_HOST_RX_VRT_TRAILER_WORDS32; + //handle the packet count / sequence number + size_t last_packet_count = _rx_stream_id_to_packet_seq[metadata.stream_id]; + if (packet_count_out != (last_packet_count+1)%16){ + std::cerr << "bad packet count: " << packet_count_out << std::endl; + } + _rx_stream_id_to_packet_seq[metadata.stream_id] = packet_count_out; //setup the rx buffer to point to the data _rx_copy_buff = boost::asio::buffer( - vrt_hdr + USRP2_HOST_RX_VRT_HEADER_WORDS32, - num_words*sizeof(uint32_t) + vrt_hdr + num_header_words32_out, + num_payload_words32_out*sizeof(uint32_t) ); } @@ -200,8 +165,9 @@ size_t usrp2_impl::send( const uhd::metadata_t &metadata, const std::string &type ){ - uint32_t *items = _tx_mem + _tx_vrt_max_offset_words32; //offset for data - size_t num_samps = _max_samples_per_packet; + uint32_t tx_mem[_mtu/sizeof(uint32_t)]; + uint32_t *items = tx_mem + vrt::max_header_words32; //offset for data + size_t num_samps = _max_tx_samples_per_packet; //calculate the number of samples to be copied //and copy the samples into the send buffer @@ -217,9 +183,26 @@ size_t usrp2_impl::send( throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%s\"") % type)); } - //send the samples (this line seems silly, will be better with vrt lib) - _tx_copy_buff = asio::buffer(items, num_samps*sizeof(uint32_t)); - return send_raw(metadata); //return num_samps; + uint32_t vrt_hdr[vrt::max_header_words32]; + 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 + vrt_hdr, //output + num_header_words32, //output + num_samps, //input + num_packet_words32, //output + packet_count //input + ); + + //copy in the vrt header (yes we left space) + std::memcpy(items - num_header_words32, vrt_hdr, num_header_words32); + asio::const_buffer send_buff(items - num_header_words32, num_packet_words32*sizeof(uint32_t)); + + //send and return number of samples + _data_transport->send(send_buff); return num_samps; } /*********************************************************************** diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 51082df15..752feb05b 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -209,11 +209,11 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){ return; case DEVICE_PROP_MAX_RX_SAMPLES: - val = size_t(_max_samples_per_packet); + val = size_t(_max_rx_samples_per_packet); return; case DEVICE_PROP_MAX_TX_SAMPLES: - val = size_t(_max_samples_per_packet); + val = size_t(_max_tx_samples_per_packet); return; } diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index a58bf8471..083ad7096 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -104,20 +105,20 @@ public: private: //the raw io interface (samples are in the usrp2 native format) - size_t send_raw(const uhd::metadata_t &); void recv_raw(uhd::metadata_t &); uhd::dict _tx_stream_id_to_packet_seq; uhd::dict _rx_stream_id_to_packet_seq; static const size_t _mtu = 1500; //FIXME we have no idea - static const size_t _max_samples_per_packet = - _mtu/sizeof(uint32_t) - + 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(uint32_t) - USRP2_HOST_RX_VRT_HEADER_WORDS32 - - USRP2_HOST_RX_VRT_TRAILER_WORDS32 - - ((2 + 14 + 20 + 8)/sizeof(uint32_t)) //size of headers (pad, eth, ip, udp) + USRP2_HOST_RX_VRT_TRAILER_WORDS32 + ; + static const size_t _max_tx_samples_per_packet = + (_mtu - _hdrs)/sizeof(uint32_t) - + uhd::transport::vrt::max_header_words32 ; - static const size_t _tx_vrt_max_offset_words32 = 7; //TODO move to future vrt lib - uint32_t _tx_mem[_mtu/sizeof(uint32_t)]; - boost::asio::const_buffer _tx_copy_buff; uhd::transport::smart_buffer::sptr _rx_smart_buff; boost::asio::const_buffer _rx_copy_buff; void io_init(void); diff --git a/host/test/vrt_test.cpp b/host/test/vrt_test.cpp index 9b2d43430..a4fad78fc 100644 --- a/host/test/vrt_test.cpp +++ b/host/test/vrt_test.cpp @@ -27,6 +27,7 @@ static void pack_and_unpack( ){ uint32_t header_buff[vrt::max_header_words32]; size_t num_header_words32; + size_t num_packet_words32; //pack metadata into a vrt header vrt::pack( @@ -34,6 +35,7 @@ static void pack_and_unpack( header_buff, //output num_header_words32, //output num_payload_words32, //input + num_packet_words32, //output packet_count //input ); @@ -48,6 +50,7 @@ static void pack_and_unpack( header_buff, //input num_header_words32_out, //output num_payload_words32_out, //output + num_packet_words32, //input packet_count_out //output ); -- cgit v1.2.3 From e531f936e6ffa645a944b360a51f82004c6cdfcb Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 3 Mar 2010 02:00:00 -0800 Subject: memcpy size fix, change to some send logic --- host/lib/usrp/usrp2/io_impl.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 9299bb04a..642b6b08b 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -198,11 +198,12 @@ size_t usrp2_impl::send( ); //copy in the vrt header (yes we left space) - std::memcpy(items - num_header_words32, vrt_hdr, num_header_words32); - asio::const_buffer send_buff(items - num_header_words32, num_packet_words32*sizeof(uint32_t)); + items -= num_header_words32; + std::memcpy(items, vrt_hdr, num_header_words32*sizeof(uint32_t)); //send and return number of samples - _data_transport->send(send_buff); return num_samps; + _data_transport->send(asio::buffer(items, num_packet_words32*sizeof(uint32_t))); + return num_samps; } /*********************************************************************** -- cgit v1.2.3 From ccd2665a29af046b0b8a11c48ffbfe2ed36ce8d9 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 3 Mar 2010 11:28:32 -0800 Subject: Split metadata into rx and tx specific metadata. The rx metadata has fragment flags and the tx metatdata has burst flags. Made the io impl for usrp2 rx routine fill in the rx metatdata fragment flag. Added device documentation for send and recv in regards to fragmentation. --- host/include/uhd/device.hpp | 21 +++++++++++++++++++-- host/include/uhd/metadata.hpp | 31 ++++++++++++++++++++----------- host/include/uhd/transport/vrt.hpp | 14 +++++++------- host/lib/CMakeLists.txt | 1 + host/lib/metadata.cpp | 37 +++++++++++++++++++++++++++++++++++++ host/lib/transport/vrt.cpp | 16 ++++++++-------- host/lib/usrp/usrp2/io_impl.cpp | 20 +++++++++++++------- host/lib/usrp/usrp2/usrp2_impl.hpp | 6 +++--- host/test/vrt_test.cpp | 12 ++++++------ 9 files changed, 114 insertions(+), 44 deletions(-) create mode 100644 host/lib/metadata.cpp diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index ba5337d33..1a52867c9 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -70,6 +70,13 @@ 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. + * It is up to the caller to call send again on the un-sent + * portions of the buffer, until the buffer is exhausted. + * * \param buff a buffer pointing to some read-only memory * \param metadata data describing the buffer's contents * \param the type of data loaded in the buffer (32fc, 16sc) @@ -77,13 +84,23 @@ public: */ virtual size_t send( const boost::asio::const_buffer &buff, - const metadata_t &metadata, + const tx_metadata_t &metadata, const std::string &type = "32fc" ) = 0; /*! * Receive a buffer containing IF data and its metadata. * + * Receive handles fragmentation as follows: + * If the buffer has insufficient space to hold all samples + * that were received in a single packet over-the-wire, + * then the buffer will be completely filled and the implementation + * will hold a pointer into the remaining portion of the packet. + * Subsequent calls will load from the remainder of the packet, + * and will flag the metadata to show that this is a fragment. + * The next call to receive, after the remainder becomes exahausted, + * will perform an over-the-wire receive as usual. + * * \param buff the buffer to fill with IF data * \param metadata data to fill describing the buffer * \param the type of data to fill into the buffer (32fc, 16sc) @@ -91,7 +108,7 @@ public: */ virtual size_t recv( const boost::asio::mutable_buffer &buff, - metadata_t &metadata, + rx_metadata_t &metadata, const std::string &type = "32fc" ) = 0; }; diff --git a/host/include/uhd/metadata.hpp b/host/include/uhd/metadata.hpp index 70842e7bc..0588ef0ed 100644 --- a/host/include/uhd/metadata.hpp +++ b/host/include/uhd/metadata.hpp @@ -23,12 +23,27 @@ namespace uhd{ /*! - * Metadata structure for describing the IF data. - * Includes stream ID, time specification, and burst flags. + * RX metadata structure for describing sent IF data. + * Includes stream ID, time specification, and fragmentation flags. * The receive routines will convert IF data headers into metadata. + */ +struct rx_metadata_t{ + uint32_t stream_id; + bool has_stream_id; + time_spec_t time_spec; + bool has_time_spec; + bool is_fragment; + + //default constructor + rx_metadata_t(void); +}; + +/*! + * TX metadata structure for describing received IF data. + * Includes stream ID, time specification, and burst flags. * The send routines will convert the metadata to IF data headers. */ -struct metadata_t{ +struct tx_metadata_t{ uint32_t stream_id; bool has_stream_id; time_spec_t time_spec; @@ -36,14 +51,8 @@ struct metadata_t{ bool start_of_burst; bool end_of_burst; - 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; - } + //default constructor + tx_metadata_t(void); }; } //namespace uhd diff --git a/host/include/uhd/transport/vrt.hpp b/host/include/uhd/transport/vrt.hpp index 2fb90a497..1700d2785 100644 --- a/host/include/uhd/transport/vrt.hpp +++ b/host/include/uhd/transport/vrt.hpp @@ -37,12 +37,12 @@ namespace vrt{ * \param packet_count the packet count sequence number */ void pack( - const metadata_t &metadata, //input - uint32_t *header_buff, //output - size_t &num_header_words32, //output - size_t num_payload_words32, //input - size_t &num_packet_words32, //output - size_t packet_count //input + const tx_metadata_t &metadata, //input + uint32_t *header_buff, //output + size_t &num_header_words32, //output + size_t num_payload_words32, //input + size_t &num_packet_words32, //output + size_t packet_count //input ); /*! @@ -55,7 +55,7 @@ namespace vrt{ * \param packet_count the packet count sequence number */ void unpack( - metadata_t &metadata, //output + rx_metadata_t &metadata, //output const uint32_t *header_buff, //input size_t &num_header_words32, //output size_t &num_payload_words32, //output diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index 390349906..b1daf22d1 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -22,6 +22,7 @@ SET(libuhd_sources device.cpp device_addr.cpp gain_handler.cpp + metadata.cpp wax.cpp transport/udp_simple.cpp transport/vrt.cpp diff --git a/host/lib/metadata.cpp b/host/lib/metadata.cpp new file mode 100644 index 000000000..40fdb7c73 --- /dev/null +++ b/host/lib/metadata.cpp @@ -0,0 +1,37 @@ +// +// 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 + +using namespace uhd; + +rx_metadata_t::rx_metadata_t(void){ + stream_id = 0; + has_stream_id = false; + time_spec = time_spec_t(); + has_time_spec = false; + is_fragment = false; +} + +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; +} diff --git a/host/lib/transport/vrt.cpp b/host/lib/transport/vrt.cpp index 19bfc1d19..5029df217 100644 --- a/host/lib/transport/vrt.cpp +++ b/host/lib/transport/vrt.cpp @@ -22,12 +22,12 @@ using namespace uhd::transport; void vrt::pack( - const metadata_t &metadata, //input - uint32_t *header_buff, //output - size_t &num_header_words32, //output - size_t num_payload_words32, //input - size_t &num_packet_words32, //output - size_t packet_count //input + const tx_metadata_t &metadata, //input + uint32_t *header_buff, //output + size_t &num_header_words32, //output + size_t num_payload_words32, //input + size_t &num_packet_words32, //output + size_t packet_count //input ){ uint32_t vrt_hdr_flags = 0; num_header_words32 = 1; @@ -58,7 +58,7 @@ void vrt::pack( } void vrt::unpack( - metadata_t &metadata, //output + rx_metadata_t &metadata, //output const uint32_t *header_buff, //input size_t &num_header_words32, //output size_t &num_payload_words32, //output @@ -66,7 +66,7 @@ void vrt::unpack( size_t &packet_count //output ){ //clear the metadata - metadata = metadata_t(); + metadata = rx_metadata_t(); //extract vrt header uint32_t vrt_hdr_word = ntohl(header_buff[0]); diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 642b6b08b..5529cfe57 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -119,7 +119,7 @@ static inline void usrp2_items_to_host_items( /*********************************************************************** * Receive Raw Data **********************************************************************/ -void usrp2_impl::recv_raw(uhd::metadata_t &metadata){ +void usrp2_impl::recv_raw(rx_metadata_t &metadata){ //do a receive _rx_smart_buff = _data_transport->recv(); @@ -161,8 +161,8 @@ void usrp2_impl::recv_raw(uhd::metadata_t &metadata){ * Send Data **********************************************************************/ size_t usrp2_impl::send( - const boost::asio::const_buffer &buff, - const uhd::metadata_t &metadata, + const asio::const_buffer &buff, + const tx_metadata_t &metadata, const std::string &type ){ uint32_t tx_mem[_mtu/sizeof(uint32_t)]; @@ -210,13 +210,19 @@ size_t usrp2_impl::send( * Receive Data **********************************************************************/ size_t usrp2_impl::recv( - const boost::asio::mutable_buffer &buff, - uhd::metadata_t &metadata, + const asio::mutable_buffer &buff, + rx_metadata_t &metadata, const std::string &type ){ //perform a receive if no rx data is waiting to be copied - if (asio::buffer_size(_rx_copy_buff) == 0) recv_raw(metadata); - //TODO otherwise flag the metadata to show that is is a fragment + if (asio::buffer_size(_rx_copy_buff) == 0){ + recv_raw(metadata); + } + //otherwise flag the metadata to show that is is a fragment + else{ + metadata = rx_metadata_t(); + metadata.is_fragment = true; + } //extract the number of samples available to copy //and a pointer into the usrp2 received items memory diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 083ad7096..f4e6054bd 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -100,12 +100,12 @@ public: double get_master_clock_freq(void); //the io interface - size_t send(const boost::asio::const_buffer &, const uhd::metadata_t &, const std::string &); - size_t recv(const boost::asio::mutable_buffer &, uhd::metadata_t &, const std::string &); + size_t send(const boost::asio::const_buffer &, const uhd::tx_metadata_t &, const std::string &); + size_t recv(const boost::asio::mutable_buffer &, uhd::rx_metadata_t &, const std::string &); private: //the raw io interface (samples are in the usrp2 native format) - void recv_raw(uhd::metadata_t &); + void recv_raw(uhd::rx_metadata_t &); uhd::dict _tx_stream_id_to_packet_seq; uhd::dict _rx_stream_id_to_packet_seq; static const size_t _mtu = 1500; //FIXME we have no idea diff --git a/host/test/vrt_test.cpp b/host/test/vrt_test.cpp index a4fad78fc..d80908c74 100644 --- a/host/test/vrt_test.cpp +++ b/host/test/vrt_test.cpp @@ -21,7 +21,7 @@ using namespace uhd::transport; static void pack_and_unpack( - const uhd::metadata_t &metadata, + const uhd::tx_metadata_t &metadata, size_t num_payload_words32, size_t packet_count ){ @@ -39,7 +39,7 @@ static void pack_and_unpack( packet_count //input ); - uhd::metadata_t metadata_out; + uhd::rx_metadata_t metadata_out; size_t num_header_words32_out; size_t num_payload_words32_out; size_t packet_count_out; @@ -70,19 +70,19 @@ static void pack_and_unpack( } BOOST_AUTO_TEST_CASE(test_with_none){ - uhd::metadata_t metadata; + uhd::tx_metadata_t metadata; pack_and_unpack(metadata, 300, 1); } BOOST_AUTO_TEST_CASE(test_with_sid){ - uhd::metadata_t metadata; + uhd::tx_metadata_t metadata; metadata.has_stream_id = true; metadata.stream_id = 6; pack_and_unpack(metadata, 400, 2); } BOOST_AUTO_TEST_CASE(test_with_time_spec){ - uhd::metadata_t metadata; + uhd::tx_metadata_t metadata; metadata.has_time_spec = true; metadata.time_spec.secs = 7; metadata.time_spec.ticks = 2000; @@ -90,7 +90,7 @@ BOOST_AUTO_TEST_CASE(test_with_time_spec){ } BOOST_AUTO_TEST_CASE(test_with_sid_and_time_spec){ - uhd::metadata_t metadata; + uhd::tx_metadata_t metadata; metadata.has_stream_id = true; metadata.stream_id = 2; metadata.has_time_spec = true; -- cgit v1.2.3 From 821c31417894bed5603dc1a18415d4a35ddd7c2d Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 3 Mar 2010 12:30:44 -0800 Subject: Some tweaks and changes to io impl that fix segfaults. Seems to work now! --- host/lib/usrp/usrp2/io_impl.cpp | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 5529cfe57..6273846dc 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -124,8 +124,12 @@ void usrp2_impl::recv_raw(rx_metadata_t &metadata){ _rx_smart_buff = _data_transport->recv(); //unpack the vrt header - const uint32_t *vrt_hdr = asio::buffer_cast(_rx_smart_buff->get()); size_t num_packet_words32 = asio::buffer_size(_rx_smart_buff->get())/sizeof(uint32_t); + if (num_packet_words32 == 0){ + _rx_copy_buff = boost::asio::buffer("", 0); + return; //must exit here after setting the buffer + } + const uint32_t *vrt_hdr = asio::buffer_cast(_rx_smart_buff->get()); size_t num_header_words32_out; size_t num_payload_words32_out; size_t packet_count_out; @@ -141,17 +145,18 @@ void usrp2_impl::recv_raw(rx_metadata_t &metadata){ }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 last_packet_count = _rx_stream_id_to_packet_seq[metadata.stream_id]; - if (packet_count_out != (last_packet_count+1)%16){ + size_t expected_packet_count = _rx_stream_id_to_packet_seq[metadata.stream_id]; + if (packet_count_out != expected_packet_count){ std::cerr << "bad packet count: " << packet_count_out << std::endl; } - _rx_stream_id_to_packet_seq[metadata.stream_id] = packet_count_out; + _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 = boost::asio::buffer( + _rx_copy_buff = asio::buffer( vrt_hdr + num_header_words32_out, num_payload_words32_out*sizeof(uint32_t) ); @@ -226,7 +231,9 @@ size_t usrp2_impl::recv( //extract the number of samples available to copy //and a pointer into the usrp2 received items memory - size_t num_samps = asio::buffer_size(_rx_copy_buff)/sizeof(uint32_t); + 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 = bytes_to_copy/sizeof(uint32_t); const uint32_t *items = asio::buffer_cast(_rx_copy_buff); //calculate the number of samples to be copied @@ -244,7 +251,9 @@ size_t usrp2_impl::recv( } //update the rx copy buffer to reflect the bytes copied - _rx_copy_buff = asio::buffer(items + num_samps, num_samps*sizeof(uint32_t)); + _rx_copy_buff = asio::buffer( + items + num_samps, bytes_to_copy - num_samps*sizeof(uint32_t) + ); return num_samps; } -- cgit v1.2.3 From bb86022d5a5f7055cdeebaeb4a55216e1a056fd4 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 4 Mar 2010 18:34:28 -0800 Subject: Moved timeouts into the udp transports. Simplified the fast path checking in the fw, but it turns out this was not the issue. Fixed some bad bit operations with the 16sc words (dont forget sign extension). Added some more documentation to the headers.... --- firmware/microblaze/apps/txrx.c | 16 ++++++++---- firmware/microblaze/lib/net_common.c | 11 -------- firmware/microblaze/lib/net_common.h | 2 -- host/include/uhd/device.hpp | 11 ++++++++ host/include/uhd/transport/udp_simple.hpp | 4 +-- host/include/uhd/transport/udp_zero_copy.hpp | 4 +-- host/lib/transport/udp_simple.cpp | 29 +++++++++++++++++++-- host/lib/transport/udp_zero_copy_none.cpp | 39 ++++++++++++++++++++++++++-- host/lib/usrp/usrp2/dsp_impl.cpp | 9 ++++--- host/lib/usrp/usrp2/io_impl.cpp | 14 +++++----- host/lib/usrp/usrp2/usrp2_impl.cpp | 39 ++++++++++------------------ 11 files changed, 115 insertions(+), 63 deletions(-) diff --git a/firmware/microblaze/apps/txrx.c b/firmware/microblaze/apps/txrx.c index 9c3caa4f2..1b3299150 100644 --- a/firmware/microblaze/apps/txrx.c +++ b/firmware/microblaze/apps/txrx.c @@ -504,16 +504,22 @@ void handle_udp_ctrl_packet( static bool eth_pkt_inspector(dbsm_t *sm, int bufno) { - //extract buffer point and length + //point me to the ethernet frame uint32_t *buff = (uint32_t *)buffer_ram(bufno); - size_t len = buffer_pool_status->last_line[bufno] - 3; //treat this as fast-path data? - if (is_udp_packet_with_vrt(buff, len, USRP2_UDP_DATA_PORT)){ - return false; - } + // We have to do this operation as fast as possible. + // Therefore, we do not check all the headers, + // just check that the udp port matches + // and that the vrt header is non zero. + // In the future, a hardware state machine will do this... + if ( //warning! magic numbers approaching.... + (((buff + ((2 + 14 + 20)/sizeof(uint32_t)))[0] & 0xffff) == USRP2_UDP_DATA_PORT) && + ((buff + ((2 + 14 + 20 + 8)/sizeof(uint32_t)))[0] != 0) + ) return false; //pass it to the slow-path handler + size_t len = buffer_pool_status->last_line[bufno] - 3; handle_eth_packet(buff, len); return true; } diff --git a/firmware/microblaze/lib/net_common.c b/firmware/microblaze/lib/net_common.c index ab7aadca9..693502d18 100644 --- a/firmware/microblaze/lib/net_common.c +++ b/firmware/microblaze/lib/net_common.c @@ -378,17 +378,6 @@ handle_arp_packet(struct arp_eth_ipv4 *p, size_t size) } } -bool is_udp_packet_with_vrt(uint32_t *p, size_t nlines, int port){ - struct ip_hdr *ip = (struct ip_hdr *)(p + 4); - struct udp_hdr *udp = (struct udp_hdr *)(((char *)ip) + IP_HLEN); - uint32_t *payload = (uint32_t *)(((char *)udp) + UDP_HLEN); - return \ - (p[3] & 0xffff) == ETHERTYPE_IPV4 && - IPH_PROTO(ip) == IP_PROTO_UDP && - udp->dest == port && - payload[0] != 0; //must be non zero vrt header -} - void handle_eth_packet(uint32_t *p, size_t nlines) { diff --git a/firmware/microblaze/lib/net_common.h b/firmware/microblaze/lib/net_common.h index 1a7052f71..6cd45bf69 100644 --- a/firmware/microblaze/lib/net_common.h +++ b/firmware/microblaze/lib/net_common.h @@ -56,6 +56,4 @@ void send_udp_pkt(int src_port, struct socket_address dst, void handle_eth_packet(uint32_t *p, size_t nlines); -bool is_udp_packet_with_vrt(uint32_t *p, size_t nlines, int port); - #endif /* INCLUDED_NET_COMMON_H */ diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index 1a52867c9..47dfa4328 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -77,6 +77,9 @@ public: * It is up to the caller to call send again on the un-sent * portions of the buffer, until the buffer is exhausted. * + * This is a blocking call and will not return until the number + * of samples returned have been read out of the buffer. + * * \param buff a buffer pointing to some read-only memory * \param metadata data describing the buffer's contents * \param the type of data loaded in the buffer (32fc, 16sc) @@ -101,6 +104,14 @@ public: * The next call to receive, after the remainder becomes exahausted, * will perform an over-the-wire receive as usual. * + * This is a blocking call and will not return until the number + * of samples returned have been written into the buffer. + * However, a call to receive may timeout and return zero samples. + * The timeout duration is decided by the underlying transport layer. + * The caller should assume that the call to receive will not return + * immediately when no packets are available to the transport layer, + * and that the timeout duration is reasonably tuned for performance. + * * \param buff the buffer to fill with IF data * \param metadata data to fill describing the buffer * \param the type of data to fill into the buffer (32fc, 16sc) diff --git a/host/include/uhd/transport/udp_simple.hpp b/host/include/uhd/transport/udp_simple.hpp index 8663128ec..0d8fcc5f0 100644 --- a/host/include/uhd/transport/udp_simple.hpp +++ b/host/include/uhd/transport/udp_simple.hpp @@ -67,9 +67,9 @@ public: /*! * Receive into the provided buffer. - * Returns empty when data is not available. + * Blocks until data is received or a timeout occurs. * \param buff a mutable buffer to receive into - * \return the number of bytes received. + * \return the number of bytes received or zero on timeout */ virtual size_t recv(const boost::asio::mutable_buffer &buff) = 0; }; diff --git a/host/include/uhd/transport/udp_zero_copy.hpp b/host/include/uhd/transport/udp_zero_copy.hpp index 9c3505dd6..1a8d822fd 100644 --- a/host/include/uhd/transport/udp_zero_copy.hpp +++ b/host/include/uhd/transport/udp_zero_copy.hpp @@ -64,9 +64,9 @@ public: /*! * Receive a buffer. + * Blocks until data is received or a timeout occurs. * The memory is managed by the implementation. - * Returns an empty buffer when data is not available. - * \return a smart buffer with memory and size + * \return a smart buffer (empty on timeout) */ virtual smart_buffer::sptr recv(void) = 0; }; diff --git a/host/lib/transport/udp_simple.cpp b/host/lib/transport/udp_simple.cpp index 491cf59db..7004bdfdf 100644 --- a/host/lib/transport/udp_simple.cpp +++ b/host/lib/transport/udp_simple.cpp @@ -16,11 +16,34 @@ // #include +#include #include #include using namespace uhd::transport; +/*********************************************************************** + * Helper Functions + **********************************************************************/ +/*! + * A receive timeout for a socket: + * + * It seems that asio cannot have timeouts with synchronous io. + * However, we can implement a polling loop that will timeout. + * This is okay bacause this is the slow-path implementation. + * + * \param socket the asio socket + */ +static void reasonable_recv_timeout( + boost::asio::ip::udp::socket &socket +){ + boost::asio::deadline_timer timer(socket.get_io_service()); + timer.expires_from_now(boost::posix_time::milliseconds(50)); + while (not (socket.available() or timer.expires_from_now().is_negative())){ + boost::this_thread::sleep(boost::posix_time::milliseconds(1)); + } +} + /*********************************************************************** * UDP connected implementation class **********************************************************************/ @@ -62,7 +85,8 @@ size_t udp_connected_impl::send(const boost::asio::const_buffer &buff){ } size_t udp_connected_impl::recv(const boost::asio::mutable_buffer &buff){ - if (_socket->available() == 0) return 0; + reasonable_recv_timeout(*_socket); + if (not _socket->available()) return 0; return _socket->receive(boost::asio::buffer(buff)); } @@ -112,7 +136,8 @@ size_t udp_broadcast_impl::send(const boost::asio::const_buffer &buff){ } size_t udp_broadcast_impl::recv(const boost::asio::mutable_buffer &buff){ - if (_socket->available() == 0) return 0; + reasonable_recv_timeout(*_socket); + if (not _socket->available()) return 0; boost::asio::ip::udp::endpoint sender_endpoint; return _socket->receive_from(boost::asio::buffer(buff), sender_endpoint); } diff --git a/host/lib/transport/udp_zero_copy_none.cpp b/host/lib/transport/udp_zero_copy_none.cpp index e95706d94..e29530cf1 100644 --- a/host/lib/transport/udp_zero_copy_none.cpp +++ b/host/lib/transport/udp_zero_copy_none.cpp @@ -16,6 +16,8 @@ // #include +#include +#include using namespace uhd::transport; @@ -67,6 +69,9 @@ public: private: boost::asio::ip::udp::socket *_socket; boost::asio::io_service _io_service; + + size_t get_recv_buff_size(void); + void set_recv_buff_size(size_t); }; udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::string &port){ @@ -81,6 +86,18 @@ udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::strin _socket = new boost::asio::ip::udp::socket(_io_service); _socket->open(boost::asio::ip::udp::v4()); _socket->connect(receiver_endpoint); + + // set the rx socket buffer size: + // pick a huge size, and deal with whatever we get + set_recv_buff_size(54321e3); //some big number! + size_t current_buff_size = get_recv_buff_size(); + std::cout << boost::format( + "Current rx socket buffer size: %d\n" + ) % current_buff_size; + if (current_buff_size < .1e6) std::cout << boost::format( + "Adjust max rx socket buffer size (linux only):\n" + " sysctl -w net.core.rmem_max=VALUE\n" + ); } udp_zero_copy_impl::~udp_zero_copy_impl(void){ @@ -92,14 +109,21 @@ size_t udp_zero_copy_impl::send(const boost::asio::const_buffer &buff){ } smart_buffer::sptr udp_zero_copy_impl::recv(void){ - size_t available = _socket->available(); + size_t available = 0; + + //implement timeout through polling and sleeping + boost::asio::deadline_timer timer(_socket->get_io_service()); + timer.expires_from_now(boost::posix_time::milliseconds(50)); + while (not ((available = _socket->available()) or timer.expires_from_now().is_negative())){ + boost::this_thread::sleep(boost::posix_time::milliseconds(1)); + } //allocate memory and create buffer uint32_t *buff_mem = new uint32_t[available/sizeof(uint32_t)]; boost::asio::mutable_buffer buff(buff_mem, available); //receive only if data is available - if (available > 0){ + if (available){ _socket->receive(boost::asio::buffer(buff)); } @@ -107,6 +131,17 @@ smart_buffer::sptr udp_zero_copy_impl::recv(void){ return smart_buffer::sptr(new smart_buffer_impl(buff)); } +size_t udp_zero_copy_impl::get_recv_buff_size(void){ + boost::asio::socket_base::receive_buffer_size option; + _socket->get_option(option); + return option.value(); +} + +void udp_zero_copy_impl::set_recv_buff_size(size_t new_size){ + boost::asio::socket_base::receive_buffer_size option(new_size); + _socket->set_option(option); +} + /*********************************************************************** * UDP zero copy make function **********************************************************************/ diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index a32f68872..7831b7667 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -21,6 +21,9 @@ using namespace uhd; +static const size_t default_decim = 16; +static const size_t default_interp = 16; + /*********************************************************************** * DDC Helper Methods **********************************************************************/ @@ -37,7 +40,7 @@ static uint32_t calculate_freq_word_and_update_actual_freq(freq_t &freq, freq_t } static uint32_t calculate_iq_scale_word(int16_t i, int16_t q){ - return ((i & 0xffff) << 16) | ((q & 0xffff) << 0); + return (uint16_t(i) << 16) | (uint16_t(q) << 0); } void usrp2_impl::init_ddc_config(void){ @@ -48,7 +51,7 @@ void usrp2_impl::init_ddc_config(void){ ); //initial config and update - _ddc_decim = 64; + _ddc_decim = default_decim; _ddc_freq = 0; update_ddc_config(); @@ -196,7 +199,7 @@ void usrp2_impl::init_duc_config(void){ ); //initial config and update - _duc_interp = 64; + _duc_interp = default_interp; _duc_freq = 0; update_duc_config(); } diff --git a/host/lib/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp index 6273846dc..cc7746720 100644 --- a/host/lib/usrp/usrp2/io_impl.cpp +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -71,9 +71,9 @@ static inline void host_floats_to_usrp2_items( size_t num_samps ){ unrolled_loop(i, num_samps,{ - int16_t real = host_floats[i].real()*shorts_per_float; - int16_t imag = host_floats[i].imag()*shorts_per_float; - usrp2_items[i] = htonl(((real << 16) & 0xffff) | ((imag << 0) & 0xffff)); + uint16_t real = host_floats[i].real()*shorts_per_float; + uint16_t imag = host_floats[i].imag()*shorts_per_float; + usrp2_items[i] = htonl((real << 16) | (imag << 0)); }); } @@ -84,8 +84,8 @@ static inline void usrp2_items_to_host_floats( ){ unrolled_loop(i, num_samps,{ uint32_t item = ntohl(usrp2_items[i]); - int16_t real = (item >> 16) & 0xffff; - int16_t imag = (item >> 0) & 0xffff; + int16_t real = item >> 16; + int16_t imag = item >> 0; host_floats[i] = fc32_t(real*floats_per_short, imag*floats_per_short); }); } @@ -130,9 +130,7 @@ void usrp2_impl::recv_raw(rx_metadata_t &metadata){ return; //must exit here after setting the buffer } const uint32_t *vrt_hdr = asio::buffer_cast(_rx_smart_buff->get()); - size_t num_header_words32_out; - size_t num_payload_words32_out; - size_t packet_count_out; + size_t num_header_words32_out, num_payload_words32_out, packet_count_out; try{ vrt::unpack( metadata, //output diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 752feb05b..58c82303f 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -24,6 +24,7 @@ using namespace uhd; using namespace uhd::usrp; using namespace uhd::transport; +namespace asio = boost::asio; /*********************************************************************** * Discovery over the udp transport @@ -43,19 +44,12 @@ uhd::device_addrs_t usrp2::discover(const device_addr_t &hint){ ctrl_data_out.id = htonl(USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO); udp_transport->send(boost::asio::buffer(&ctrl_data_out, sizeof(ctrl_data_out))); - //loop and recieve until the time is up - size_t num_timeouts = 0; + //loop and recieve until the timeout while(true){ usrp2_ctrl_data_t ctrl_data_in; - size_t len = udp_transport->recv( - boost::asio::buffer(&ctrl_data_in, sizeof(ctrl_data_in)) - ); + size_t len = udp_transport->recv(asio::buffer(&ctrl_data_in, sizeof(ctrl_data_in))); //std::cout << len << "\n"; - if (len < sizeof(usrp2_ctrl_data_t)){ - //sleep a little so we dont burn cpu - if (num_timeouts++ > 50) break; - boost::this_thread::sleep(boost::posix_time::milliseconds(1)); - }else{ + 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: @@ -67,9 +61,11 @@ uhd::device_addrs_t usrp2::discover(const device_addr_t &hint){ new_addr["transport"] = "udp"; new_addr["addr"] = ip_addr.to_string(); usrp2_addrs.push_back(new_addr); - break; + //dont break here, it will exit the while loop + //just continue on to the next loop iteration } } + if (len == 0) break; //timeout } return usrp2_addrs; @@ -164,24 +160,15 @@ usrp2_ctrl_data_t usrp2_impl::ctrl_send_and_recv(const usrp2_ctrl_data_t &out_da out_copy.seq = htonl(++_ctrl_seq_num); _ctrl_transport->send(boost::asio::buffer(&out_copy, sizeof(usrp2_ctrl_data_t))); - //loop and recieve until the time is up - size_t num_timeouts = 0; + //loop until we get the packet or timeout while(true){ usrp2_ctrl_data_t in_data; - size_t len = _ctrl_transport->recv( - boost::asio::buffer(&in_data, sizeof(in_data)) - ); - if (len < sizeof(usrp2_ctrl_data_t)){ - //sleep a little so we dont burn cpu - if (num_timeouts++ > 50) break; - boost::this_thread::sleep(boost::posix_time::milliseconds(1)); - }else{ - //handle the received data - if (ntohl(in_data.seq) == _ctrl_seq_num){ - return in_data; - } - //didnt get seq, continue on... + size_t len = _ctrl_transport->recv(asio::buffer(&in_data, sizeof(in_data))); + if (len >= sizeof(usrp2_ctrl_data_t) and ntohl(in_data.seq) == _ctrl_seq_num){ + return in_data; } + if (len == 0) break; //timeout + //didnt get seq or bad packet, continue looking... } throw std::runtime_error("usrp2 no control response"); } -- cgit v1.2.3 From 8e9a8464386db03a596e0b88d0714d22723d37d0 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 10 Mar 2010 14:47:03 -0800 Subject: Added simple device to handle wrapping general properties up into simple api. Added setting time capability to the usrp2 impl. Messing with props and time specs... --- firmware/microblaze/apps/txrx.c | 10 ++ host/apps/discover_usrps.cpp | 2 +- host/include/uhd/CMakeLists.txt | 1 + host/include/uhd/props.hpp | 20 +-- host/include/uhd/simple_device.hpp | 111 +++++++++++++ host/include/uhd/time_spec.hpp | 19 ++- host/include/uhd/utils.hpp | 105 ++++++------- host/lib/CMakeLists.txt | 2 + host/lib/simple_device.cpp | 303 ++++++++++++++++++++++++++++++++++++ host/lib/time_spec.cpp | 40 +++++ host/lib/usrp/usrp2/dboard_impl.cpp | 9 +- host/lib/usrp/usrp2/dsp_impl.cpp | 21 +-- host/lib/usrp/usrp2/fw_common.h | 8 + host/lib/usrp/usrp2/mboard_impl.cpp | 35 ++++- host/lib/usrp/usrp2/usrp2_impl.hpp | 1 + 15 files changed, 591 insertions(+), 96 deletions(-) create mode 100644 host/include/uhd/simple_device.hpp create mode 100644 host/lib/simple_device.cpp create mode 100644 host/lib/time_spec.cpp diff --git a/firmware/microblaze/apps/txrx.c b/firmware/microblaze/apps/txrx.c index 1b3299150..18bbdd23d 100644 --- a/firmware/microblaze/apps/txrx.c +++ b/firmware/microblaze/apps/txrx.c @@ -489,6 +489,16 @@ void handle_udp_ctrl_packet( ctrl_data_out.id = USRP2_CTRL_ID_TOTALLY_SETUP_THE_DUC_DUDE; break; + /******************************************************************* + * Time Config + ******************************************************************/ + case USRP2_CTRL_ID_GOT_A_NEW_TIME_FOR_YOU_BRO: + sr_time64->imm = (ctrl_data_in->data.time_args.now == 0)? 0 : 1; + sr_time64->ticks = ctrl_data_in->data.time_args.ticks; + sr_time64->secs = ctrl_data_in->data.time_args.secs; //set this last to latch the regs + ctrl_data_out.id = USRP2_CTRL_ID_SWEET_I_GOT_THAT_TIME_DUDE; + break; + default: ctrl_data_out.id = USRP2_CTRL_ID_HUH_WHAT; diff --git a/host/apps/discover_usrps.cpp b/host/apps/discover_usrps.cpp index 448095726..d670d1651 100644 --- a/host/apps/discover_usrps.cpp +++ b/host/apps/discover_usrps.cpp @@ -63,7 +63,7 @@ int main(int argc, char *argv[]){ std::cout << "-- USRP Device " << i << std::endl; std::cout << "--------------------------------------------------" << std::endl; std::cout << device_addrs[i] << std::endl << std::endl; - //uhd::device::make(device_addrs[i]); //test make + uhd::device::make(device_addrs[i]); //test make } return 0; diff --git a/host/include/uhd/CMakeLists.txt b/host/include/uhd/CMakeLists.txt index f4fb96786..522f43afd 100644 --- a/host/include/uhd/CMakeLists.txt +++ b/host/include/uhd/CMakeLists.txt @@ -26,6 +26,7 @@ INSTALL(FILES gain_handler.hpp metadata.hpp props.hpp + simple_device.hpp time_spec.hpp utils.hpp wax.hpp diff --git a/host/include/uhd/props.hpp b/host/include/uhd/props.hpp index cf301d4bd..dea2baf52 100644 --- a/host/include/uhd/props.hpp +++ b/host/include/uhd/props.hpp @@ -116,16 +116,16 @@ namespace uhd{ enum dboard_prop_t{ DBOARD_PROP_NAME, //ro, std::string DBOARD_PROP_SUBDEV, //ro, wax::obj - DBOARD_PROP_SUBDEV_NAMES, //ro, prop_names_t - DBOARD_PROP_CODEC //ro, wax::obj - }; + DBOARD_PROP_SUBDEV_NAMES //ro, prop_names_t + //DBOARD_PROP_CODEC //ro, wax::obj //----> not sure, dont have to deal with yet + }; - /*! + /*! ------ not dealing with yet, commented out ------------ * Possible device codec properties: * A codec is expected to have a rate and gain elements. * Other properties can be discovered through the others prop. */ - enum codec_prop_t{ + /*enum codec_prop_t{ CODEC_PROP_NAME, //ro, std::string CODEC_PROP_OTHERS, //ro, prop_names_t CODEC_PROP_GAIN, //rw, gain_t @@ -133,8 +133,8 @@ namespace uhd{ CODEC_PROP_GAIN_MIN, //ro, gain_t CODEC_PROP_GAIN_STEP, //ro, gain_t CODEC_PROP_GAIN_NAMES, //ro, prop_names_t - CODEC_PROP_CLOCK_RATE //ro, freq_t - }; + //CODEC_PROP_CLOCK_RATE //ro, freq_t //----> not sure we care to know + };*/ /*! * Possible device subdev properties @@ -156,9 +156,9 @@ namespace uhd{ SUBDEV_PROP_QUADRATURE, //ro, bool SUBDEV_PROP_IQ_SWAPPED, //ro, bool SUBDEV_PROP_SPECTRUM_INVERTED, //ro, bool - SUBDEV_PROP_IS_TX, //ro, bool - SUBDEV_PROP_RSSI, //ro, gain_t - SUBDEV_PROP_BANDWIDTH //rw, freq_t + SUBDEV_PROP_LO_INTERFERES //ro, bool + //SUBDEV_PROP_RSSI, //ro, gain_t //----> not on all boards, use named prop + //SUBDEV_PROP_BANDWIDTH //rw, freq_t //----> not on all boards, use named prop }; } //namespace uhd diff --git a/host/include/uhd/simple_device.hpp b/host/include/uhd/simple_device.hpp new file mode 100644 index 000000000..64ec85a5c --- /dev/null +++ b/host/include/uhd/simple_device.hpp @@ -0,0 +1,111 @@ +// +// 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 + +#ifndef INCLUDED_UHD_SIMPLE_DEVICE_HPP +#define INCLUDED_UHD_SIMPLE_DEVICE_HPP + +namespace uhd{ + +/*! + * The tune result struct holds result of a 2-phase tuning: + * The struct hold the result of tuning the dboard as + * the target and actual intermediate frequency. + * The struct hold the result of tuning the DDC/DUC as + * the target and actual digital converter frequency. + * It also tell us weather or not the spectrum is inverted. + */ +struct tune_result_t{ + double target_inter_freq; + double actual_inter_freq; + double target_dxc_freq; + double actual_dxc_freq; + bool spectrum_inverted; + tune_result_t(void); +}; + +/*! + * The simple UHD device class: + * A simple device facilitates ease-of-use for most use-case scenarios. + * The wrapper provides convenience functions to tune the devices + * as well as to set the dboard gains, antennas, and other properties. + */ +class simple_device : boost::noncopyable{ +public: + typedef boost::shared_ptr sptr; + static sptr make(const std::string &args); + + virtual device::sptr get_device(void) = 0; + + virtual std::string get_name(void) = 0; + + /******************************************************************* + * Streaming + ******************************************************************/ + virtual void set_streaming(bool enb) = 0; + virtual bool get_streaming(void) = 0; + + /******************************************************************* + * RX methods + ******************************************************************/ + virtual void set_rx_rate(double rate) = 0; + virtual double get_rx_rate(void) = 0; + virtual std::vector get_rx_rates(void) = 0; + + virtual tune_result_t set_rx_freq(double target_freq, double lo_offset) = 0; + virtual double get_rx_freq_min(void) = 0; + virtual double get_rx_freq_max(void) = 0; + + virtual void set_rx_gain(float gain) = 0; + virtual float get_rx_gain(void) = 0; + virtual float get_rx_gain_min(void) = 0; + virtual float get_rx_gain_max(void) = 0; + virtual float get_rx_gain_step(void) = 0; + + virtual void set_rx_antenna(const std::string &ant) = 0; + virtual std::string get_rx_antenna(void) = 0; + virtual std::vector get_rx_antennas(void) = 0; + + /******************************************************************* + * TX methods + ******************************************************************/ + virtual void set_tx_rate(double rate) = 0; + virtual double get_tx_rate(void) = 0; + virtual std::vector get_tx_rates(void) = 0; + + virtual tune_result_t set_tx_freq(double target_freq, double lo_offset) = 0; + virtual double get_tx_freq_min(void) = 0; + virtual double get_tx_freq_max(void) = 0; + + virtual void set_tx_gain(float gain) = 0; + virtual float get_tx_gain(void) = 0; + virtual float get_tx_gain_min(void) = 0; + virtual float get_tx_gain_max(void) = 0; + virtual float get_tx_gain_step(void) = 0; + + virtual void set_tx_antenna(const std::string &ant) = 0; + virtual std::string get_tx_antenna(void) = 0; + virtual std::vector get_tx_antennas(void) = 0; +}; + +} //namespace uhd + +#endif /* INCLUDED_UHD_SIMPLE_DEVICE_HPP */ diff --git a/host/include/uhd/time_spec.hpp b/host/include/uhd/time_spec.hpp index e5657e555..7e182236b 100644 --- a/host/include/uhd/time_spec.hpp +++ b/host/include/uhd/time_spec.hpp @@ -15,6 +15,7 @@ // along with this program. If not, see . // +#include #include #ifndef INCLUDED_UHD_TIME_SPEC_HPP @@ -36,20 +37,22 @@ namespace uhd{ * Create a time_spec_t that holds a wildcard time. * This will have implementation-specific meaning. */ - time_spec_t(void){ - secs = ~0; - ticks = ~0; - } + time_spec_t(void); /*! * Create a time_spec_t from seconds and ticks. * \param new_secs the new seconds * \param new_ticks the new ticks (default = 0) */ - time_spec_t(uint32_t new_secs, uint32_t new_ticks = 0){ - secs = new_secs; - ticks = new_ticks; - } + time_spec_t(uint32_t new_secs, uint32_t new_ticks = 0); + + /*! + * Create a time_spec_t from boost posix time. + * \param time fine-grained boost posix time + * \param tick_rate the rate of ticks per second + */ + time_spec_t(boost::posix_time::ptime time, double tick_rate); + }; } //namespace uhd diff --git a/host/include/uhd/utils.hpp b/host/include/uhd/utils.hpp index 9bbdc83c9..25a7b5abd 100644 --- a/host/include/uhd/utils.hpp +++ b/host/include/uhd/utils.hpp @@ -15,18 +15,14 @@ // along with this program. If not, see . // -#include -#include -#include -#include -#include -#include -#include -#include - #ifndef INCLUDED_UHD_UTILS_HPP #define INCLUDED_UHD_UTILS_HPP +#include +#include +#include +#include + /*! * Useful templated functions and classes that I like to pretend are part of stl */ @@ -40,7 +36,9 @@ namespace std{ }; #define ASSERT_THROW(_x) if (not (_x)) { \ - throw std::assert_error("Assertion Failed: " + std::string(#_x)); \ + throw std::assert_error(str(boost::format( \ + "Assertion Failed:\n %s:%d\n %s\n __/ %s __/" \ + ) % __FILE__ % __LINE__ % BOOST_CURRENT_FUNCTION % std::string(#_x))); \ } template @@ -57,9 +55,9 @@ namespace std{ return last != std::find(first, last, elem); } - template - bool has(const V &vector, const T &elem){ - return has(vector.begin(), vector.end(), elem); + template + bool has(const Iterable &iterable, const T &elem){ + return has(iterable.begin(), iterable.end(), elem); } template @@ -75,52 +73,43 @@ namespace std{ }//namespace std -/*namespace uhd{ - -inline void tune( - freq_t target_freq, - freq_t lo_offset, - wax::obj subdev_freq_proxy, - bool subdev_quadrature, - bool subdev_spectrum_inverted, - bool subdev_is_tx, - wax::obj dsp_freq_proxy, - freq_t dsp_sample_rate -){ - // Ask the d'board to tune as closely as it can to target_freq+lo_offset - subdev_freq_proxy = target_freq + lo_offset; - freq_t inter_freq = wax::cast(subdev_freq_proxy); - - // Calculate the DDC setting that will downconvert the baseband from the - // daughterboard to our target frequency. - freq_t delta_freq = target_freq - inter_freq; - freq_t delta_sign = std::signum(delta_freq); - delta_freq *= delta_sign; - delta_freq = fmod(delta_freq, dsp_sample_rate); - bool inverted = delta_freq > dsp_sample_rate/2.0; - freq_t dxc_freq = inverted? (delta_freq - dsp_sample_rate) : (-delta_freq); - dxc_freq *= delta_sign; - - // If the spectrum is inverted, and the daughterboard doesn't do - // quadrature downconversion, we can fix the inversion by flipping the - // sign of the dxc_freq... (This only happens using the basic_rx board) - if (subdev_spectrum_inverted){ - inverted = not inverted; - } - if (inverted and not subdev_quadrature){ - dxc_freq = -dxc_freq; - inverted = not inverted; - } - if (subdev_is_tx){ - dxc_freq = -dxc_freq; // down conversion versus up conversion +#include +#include +#include + +namespace uhd{ + + /*! + * Check that an element is found in a container. + * If not, throw a meaningful assertion error. + * The "what" in the error will show what is + * being set and a list of known good values. + * + * \param iterable a list of possible settings + * \param elem an element that may be in the list + * \param what a description of what is being set + * \throw assertion_error when elem not in list + */ + template void assert_has( + const Iterable &iterable, + const T &elem, + const std::string &what = "unknown" + ){ + if (std::has(iterable, elem)) return; + std::string possible_values = ""; + BOOST_FOREACH(T e, iterable){ + if (e != iterable.begin()[0]) possible_values += ", "; + possible_values += boost::lexical_cast(e); + } + throw std::assert_error(str(boost::format( + "Error: %s is not a valid %s. " + "Possible values are: [%s]." + ) + % boost::lexical_cast(elem) + % what % possible_values + )); } - dsp_freq_proxy = dxc_freq; - //freq_t actual_dxc_freq = wax::cast(dsp_freq_proxy); - - //return some kind of tune result tuple/struct -} - -} //namespace uhd*/ +}//namespace uhd #endif /* INCLUDED_UHD_UTILS_HPP */ diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index b1daf22d1..b141d67bb 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -23,6 +23,8 @@ SET(libuhd_sources device_addr.cpp gain_handler.cpp metadata.cpp + simple_device.cpp + time_spec.cpp wax.cpp transport/udp_simple.cpp transport/vrt.cpp diff --git a/host/lib/simple_device.cpp b/host/lib/simple_device.cpp new file mode 100644 index 000000000..63a17c52d --- /dev/null +++ b/host/lib/simple_device.cpp @@ -0,0 +1,303 @@ +// +// 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 +#include +#include +#include + +using namespace uhd; + +tune_result_t::tune_result_t(void){ + /* NOP */ +} + +/*********************************************************************** + * Tune Helper Function + **********************************************************************/ +static tune_result_t tune( + double target_freq, + double lo_offset, + wax::obj subdev, + wax::obj dxc, + bool is_tx +){ + wax::obj subdev_freq_proxy = subdev[SUBDEV_PROP_FREQ]; + bool subdev_quadrature = wax::cast(subdev[SUBDEV_PROP_QUADRATURE]); + bool subdev_spectrum_inverted = wax::cast(subdev[SUBDEV_PROP_SPECTRUM_INVERTED]); + wax::obj dxc_freq_proxy = dxc[std::string("freq")]; + double dxc_sample_rate = wax::cast(dxc[std::string("rate")]); + + // Ask the d'board to tune as closely as it can to target_freq+lo_offset + double target_inter_freq = target_freq + lo_offset; + subdev_freq_proxy = target_inter_freq; + double actual_inter_freq = wax::cast(subdev_freq_proxy); + + // Calculate the DDC setting that will downconvert the baseband from the + // daughterboard to our target frequency. + double delta_freq = target_freq - actual_inter_freq; + double delta_sign = std::signum(delta_freq); + delta_freq *= delta_sign; + delta_freq = fmod(delta_freq, dxc_sample_rate); + bool inverted = delta_freq > dxc_sample_rate/2.0; + double target_dxc_freq = inverted? (delta_freq - dxc_sample_rate) : (-delta_freq); + target_dxc_freq *= delta_sign; + + // If the spectrum is inverted, and the daughterboard doesn't do + // quadrature downconversion, we can fix the inversion by flipping the + // sign of the dxc_freq... (This only happens using the basic_rx board) + if (subdev_spectrum_inverted){ + inverted = not inverted; + } + if (inverted and not subdev_quadrature){ + target_dxc_freq *= -1.0; + inverted = not inverted; + } + // down conversion versus up conversion, fight! + // your mother is ugly and your going down... + target_dxc_freq *= (is_tx)? -1.0 : +1.0; + + dxc_freq_proxy = target_dxc_freq; + double actual_dxc_freq = wax::cast(dxc_freq_proxy); + + //return some kind of tune result tuple/struct + tune_result_t tune_result; + tune_result.target_inter_freq = target_inter_freq; + tune_result.actual_inter_freq = actual_inter_freq; + tune_result.target_dxc_freq = target_dxc_freq; + tune_result.actual_dxc_freq = actual_dxc_freq; + tune_result.spectrum_inverted = inverted; + return tune_result; +} + +/*********************************************************************** + * Helper Functions + **********************************************************************/ +static std::string trim(const std::string &in){ + return boost::algorithm::trim_copy(in); +} + +device_addr_t args_to_device_addr(const std::string &args){ + device_addr_t addr; + + //split the args at the semi-colons + std::vector pairs; + boost::split(pairs, args, boost::is_any_of(";")); + BOOST_FOREACH(std::string pair, pairs){ + if (trim(pair) == "") continue; + + //split the key value pairs at the equals + std::vector key_val; + boost::split(key_val, pair, boost::is_any_of("=")); + if (key_val.size() != 2) throw std::runtime_error("invalid args string: "+args); + addr[trim(key_val[0])] = trim(key_val[1]); + } + + return addr; +} + +static std::vector get_xx_rates(wax::obj decerps, wax::obj rate){ + std::vector rates; + BOOST_FOREACH(size_t decerp, wax::cast >(decerps)){ + rates.push_back(wax::cast(rate)/decerp); + } + return rates; +} + +/*********************************************************************** + * Simple Device Implementation + **********************************************************************/ +class simple_device_impl : public simple_device{ +public: + simple_device_impl(const device_addr_t &addr){ + _dev = device::make(addr); + _mboard = (*_dev)[DEVICE_PROP_MBOARD]; + _rx_ddc = _mboard[named_prop_t(MBOARD_PROP_RX_DSP, "ddc0")]; + _tx_duc = _mboard[named_prop_t(MBOARD_PROP_TX_DSP, "duc0")]; + _rx_subdev = _mboard[MBOARD_PROP_RX_DBOARD][DBOARD_PROP_SUBDEV]; + _tx_subdev = _mboard[MBOARD_PROP_TX_DBOARD][DBOARD_PROP_SUBDEV]; + } + + ~simple_device_impl(void){ + /* NOP */ + } + + device::sptr get_device(void){ + return _dev; + } + + std::string get_name(void){ + return wax::cast(_mboard[MBOARD_PROP_NAME]); + } + + /******************************************************************* + * Streaming + ******************************************************************/ + void set_streaming(bool enb){ + _rx_ddc[std::string("enabled")] = enb; + } + + bool get_streaming(void){ + return wax::cast(_rx_ddc[std::string("enabled")]); + } + + /******************************************************************* + * RX methods + ******************************************************************/ + void set_rx_rate(double rate){ + double samp_rate = wax::cast(_rx_ddc[std::string("rate")]); + assert_has(get_rx_rates(), rate, "simple device rx rate"); + _rx_ddc[std::string("decim")] = size_t(samp_rate/rate); + } + + double get_rx_rate(void){ + double samp_rate = wax::cast(_rx_ddc[std::string("rate")]); + size_t decim = wax::cast(_rx_ddc[std::string("decim")]); + return samp_rate/decim; + } + + std::vector get_rx_rates(void){ + return get_xx_rates(_rx_ddc[std::string("decims")], _rx_ddc[std::string("rate")]); + } + + tune_result_t set_rx_freq(double target_freq, double lo_offset){ + return tune(target_freq, lo_offset, _rx_subdev, _rx_ddc, false/* not tx */); + } + + double get_rx_freq_min(void){ + return wax::cast(_rx_subdev[SUBDEV_PROP_FREQ_MIN]); + } + + double get_rx_freq_max(void){ + return wax::cast(_rx_subdev[SUBDEV_PROP_FREQ_MAX]); + } + + void set_rx_gain(float gain){ + _rx_subdev[SUBDEV_PROP_GAIN] = gain; + } + + float get_rx_gain(void){ + return wax::cast(_rx_subdev[SUBDEV_PROP_GAIN]); + } + + float get_rx_gain_min(void){ + return wax::cast(_rx_subdev[SUBDEV_PROP_GAIN_MIN]); + } + + float get_rx_gain_max(void){ + return wax::cast(_rx_subdev[SUBDEV_PROP_GAIN_MAX]); + } + + float get_rx_gain_step(void){ + return wax::cast(_rx_subdev[SUBDEV_PROP_GAIN_STEP]); + } + + void set_rx_antenna(const std::string &ant){ + _rx_subdev[SUBDEV_PROP_ANTENNA] = ant; + } + + std::string get_rx_antenna(void){ + return wax::cast(_rx_subdev[SUBDEV_PROP_ANTENNA]); + } + + std::vector get_rx_antennas(void){ + return wax::cast >(_rx_subdev[SUBDEV_PROP_ANTENNA_NAMES]); + } + + /******************************************************************* + * TX methods + ******************************************************************/ + void set_tx_rate(double rate){ + double samp_rate = wax::cast(_tx_duc[std::string("rate")]); + assert_has(get_tx_rates(), rate, "simple device tx rate"); + _tx_duc[std::string("interp")] = size_t(samp_rate/rate); + } + + double get_tx_rate(void){ + double samp_rate = wax::cast(_tx_duc[std::string("rate")]); + size_t interp = wax::cast(_tx_duc[std::string("interp")]); + return samp_rate/interp; + } + + std::vector get_tx_rates(void){ + return get_xx_rates(_tx_duc[std::string("interps")], _tx_duc[std::string("rate")]); + } + + tune_result_t set_tx_freq(double target_freq, double lo_offset){ + return tune(target_freq, lo_offset, _tx_subdev, _tx_duc, true/* is tx */); + } + + double get_tx_freq_min(void){ + return wax::cast(_tx_subdev[SUBDEV_PROP_FREQ_MIN]); + } + + double get_tx_freq_max(void){ + return wax::cast(_tx_subdev[SUBDEV_PROP_FREQ_MAX]); + } + + void set_tx_gain(float gain){ + _tx_subdev[SUBDEV_PROP_GAIN] = gain; + } + + float get_tx_gain(void){ + return wax::cast(_tx_subdev[SUBDEV_PROP_GAIN]); + } + + float get_tx_gain_min(void){ + return wax::cast(_tx_subdev[SUBDEV_PROP_GAIN_MIN]); + } + + float get_tx_gain_max(void){ + return wax::cast(_tx_subdev[SUBDEV_PROP_GAIN_MAX]); + } + + float get_tx_gain_step(void){ + return wax::cast(_tx_subdev[SUBDEV_PROP_GAIN_STEP]); + } + + void set_tx_antenna(const std::string &ant){ + _tx_subdev[SUBDEV_PROP_ANTENNA] = ant; + } + + std::string get_tx_antenna(void){ + return wax::cast(_tx_subdev[SUBDEV_PROP_ANTENNA]); + } + + std::vector get_tx_antennas(void){ + return wax::cast >(_tx_subdev[SUBDEV_PROP_ANTENNA_NAMES]); + } + +private: + device::sptr _dev; + wax::obj _mboard; + wax::obj _rx_ddc; + wax::obj _tx_duc; + wax::obj _rx_subdev; + wax::obj _tx_subdev; +}; + +/*********************************************************************** + * The Make Function + **********************************************************************/ +simple_device::sptr simple_device::make(const std::string &args){ + return sptr(new simple_device_impl(args_to_device_addr(args))); +} diff --git a/host/lib/time_spec.cpp b/host/lib/time_spec.cpp new file mode 100644 index 000000000..193441342 --- /dev/null +++ b/host/lib/time_spec.cpp @@ -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 . +// + +#include + +using namespace uhd; + +time_spec_t::time_spec_t(void){ + secs = ~0; + ticks = ~0; +} + +time_spec_t::time_spec_t(uint32_t new_secs, uint32_t new_ticks){ + secs = new_secs; + ticks = new_ticks; +} + +static const boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1)); +static double time_tick_rate(boost::posix_time::time_duration::ticks_per_second()); + +time_spec_t::time_spec_t(boost::posix_time::ptime time, double tick_rate){ + boost::posix_time::time_duration td = time - epoch; + secs = td.total_seconds(); + double time_ticks_per_device_ticks = time_tick_rate/tick_rate; + ticks = td.fractional_seconds()/time_ticks_per_device_ticks; +} diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp index 32c64f541..da05c3241 100644 --- a/host/lib/usrp/usrp2/dboard_impl.cpp +++ b/host/lib/usrp/usrp2/dboard_impl.cpp @@ -16,6 +16,7 @@ // #include +#include #include "usrp2_impl.hpp" #include "dboard_interface.hpp" @@ -83,8 +84,8 @@ void usrp2_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){ val = _dboard_manager->get_rx_subdev_names(); return; - case DBOARD_PROP_CODEC: - throw std::runtime_error("unhandled prop in usrp2 dboard"); + //case DBOARD_PROP_CODEC: + // throw std::runtime_error("unhandled prop in usrp2 dboard"); } } @@ -113,8 +114,8 @@ void usrp2_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){ val = _dboard_manager->get_tx_subdev_names(); return; - case DBOARD_PROP_CODEC: - throw std::runtime_error("unhandled prop in usrp2 dboard"); + //case DBOARD_PROP_CODEC: + // throw std::runtime_error("unhandled prop in usrp2 dboard"); } } diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index 7831b7667..cb7f58ec8 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -16,6 +16,7 @@ // #include +#include #include #include "usrp2_impl.hpp" @@ -110,7 +111,7 @@ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){ prop_names_t others = boost::assign::list_of ("rate") ("decim") - ("decim_rates") + ("decims") ("freq") ("enabled") ("stream_at") @@ -131,7 +132,7 @@ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){ val = _ddc_decim; return; } - else if (key_name == "decim_rates"){ + else if (key_name == "decims"){ val = _allowed_decim_and_interp_rates; return; } @@ -154,10 +155,10 @@ void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){ std::string key_name = wax::cast(key); if (key_name == "decim"){ size_t new_decim = wax::cast(val); - ASSERT_THROW(std::has( + assert_has( _allowed_decim_and_interp_rates, - new_decim - )); + new_decim, "usrp2 decimation" + ); _ddc_decim = new_decim; //shadow update_ddc_config(); return; @@ -244,7 +245,7 @@ void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){ prop_names_t others = boost::assign::list_of ("rate") ("interp") - ("interp_rates") + ("interps") ("freq") ; val = others; @@ -263,7 +264,7 @@ void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){ val = _duc_interp; return; } - else if (key_name == "interp_rates"){ + else if (key_name == "interps"){ val = _allowed_decim_and_interp_rates; return; } @@ -282,10 +283,10 @@ void usrp2_impl::duc_set(const wax::obj &key, const wax::obj &val){ std::string key_name = wax::cast(key); if (key_name == "interp"){ size_t new_interp = wax::cast(val); - ASSERT_THROW(std::has( + assert_has( _allowed_decim_and_interp_rates, - new_interp - )); + new_interp, "usrp2 interpolation" + ); _duc_interp = new_interp; //shadow update_duc_config(); return; diff --git a/host/lib/usrp/usrp2/fw_common.h b/host/lib/usrp/usrp2/fw_common.h index 8e4b2ba35..10c1ef8cf 100644 --- a/host/lib/usrp/usrp2/fw_common.h +++ b/host/lib/usrp/usrp2/fw_common.h @@ -91,6 +91,9 @@ typedef enum{ USRP2_CTRL_ID_SETUP_THIS_DUC_FOR_ME_BRO, USRP2_CTRL_ID_TOTALLY_SETUP_THE_DUC_DUDE, + USRP2_CTRL_ID_GOT_A_NEW_TIME_FOR_YOU_BRO, + USRP2_CTRL_ID_SWEET_I_GOT_THAT_TIME_DUDE, + USRP2_CTRL_ID_PEACE_OUT } usrp2_ctrl_id_t; @@ -186,6 +189,11 @@ typedef struct{ uint32_t interp; uint32_t scale_iq; } duc_args; + struct { + uint32_t secs; + uint32_t ticks; + uint8_t now; + } time_args; } data; } usrp2_ctrl_data_t; diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 8e682a675..47e22c473 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -28,6 +28,10 @@ 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 the time on the usrp2 as close as possible to the system utc time + boost::posix_time::ptime now(boost::posix_time::microsec_clock::universal_time()); + set_time_spec(time_spec_t(now, get_master_clock_freq()), true); } void usrp2_impl::init_clock_config(void){ @@ -64,6 +68,19 @@ void usrp2_impl::update_clock_config(void){ ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_GOT_THE_NEW_CLOCK_CONFIG_DUDE); } +void usrp2_impl::set_time_spec(const time_spec_t &time_spec, bool now){ + //setup the out data + usrp2_ctrl_data_t out_data; + out_data.id = htonl(USRP2_CTRL_ID_GOT_A_NEW_TIME_FOR_YOU_BRO); + out_data.data.time_args.secs = htonl(time_spec.secs); + out_data.data.time_args.ticks = htonl(time_spec.ticks); + out_data.data.time_args.now = (now)? 1 : 0; + + //send and recv + usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); + ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_SWEET_I_GOT_THAT_TIME_DUDE); +} + /*********************************************************************** * MBoard Get Properties **********************************************************************/ @@ -157,7 +174,7 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){ case MBOARD_PROP_PPS_SOURCE:{ std::string name = wax::cast(val); - ASSERT_THROW(_pps_source_dict.has_key(name)); + assert_has(_pps_source_dict.get_keys(), name, "usrp2 pps source"); _pps_source = name; //shadow update_clock_config(); } @@ -165,7 +182,7 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){ case MBOARD_PROP_PPS_POLARITY:{ std::string name = wax::cast(val); - ASSERT_THROW(_pps_polarity_dict.has_key(name)); + assert_has(_pps_polarity_dict.get_keys(), name, "usrp2 pps polarity"); _pps_polarity = name; //shadow update_clock_config(); } @@ -173,12 +190,22 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){ case MBOARD_PROP_REF_SOURCE:{ std::string name = wax::cast(val); - ASSERT_THROW(_ref_source_dict.has_key(name)); + assert_has(_ref_source_dict.get_keys(), name, "usrp2 reference source"); _ref_source = name; //shadow update_clock_config(); } return; + case MBOARD_PROP_TIME_NOW:{ + set_time_spec(wax::cast(val), true); + return; + } + + case MBOARD_PROP_TIME_NEXT_PPS:{ + set_time_spec(wax::cast(val), false); + return; + } + case MBOARD_PROP_NAME: case MBOARD_PROP_OTHERS: case MBOARD_PROP_CLOCK_RATE: @@ -192,8 +219,6 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){ case MBOARD_PROP_TX_DBOARD_NAMES: case MBOARD_PROP_PPS_SOURCE_NAMES: case MBOARD_PROP_REF_SOURCE_NAMES: - case MBOARD_PROP_TIME_NOW: - case MBOARD_PROP_TIME_NEXT_PPS: throw std::runtime_error("Error: trying to set read-only property on usrp2 mboard"); } diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index f4e6054bd..fc713c2bf 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -135,6 +135,7 @@ private: std::string _pps_source, _pps_polarity, _ref_source; void init_clock_config(void); void update_clock_config(void); + void set_time_spec(const uhd::time_spec_t &time_spec, bool now); //mappings from clock config strings to over the wire enums uhd::dict _pps_source_dict; -- cgit v1.2.3 From 9c0fb5e15da3c8ccbc1c8537671703411b210fcf Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Wed, 10 Mar 2010 19:33:38 -0800 Subject: Filled in dboard code for basics and lf type boards. The dboard is now just a uint16 (dont bother with the enums). The dboard manager now registers subdevs with a name. The basic board code uses a static block to register itself. --- host/include/uhd/simple_device.hpp | 4 +- host/include/uhd/usrp/dboard_base.hpp | 5 +- host/include/uhd/usrp/dboard_id.hpp | 9 +- host/include/uhd/usrp/dboard_manager.hpp | 2 + host/include/uhd/utils.hpp | 5 + host/lib/CMakeLists.txt | 1 - host/lib/simple_device.cpp | 14 +- host/lib/usrp/dboard/basic.cpp | 282 +++++++++++++++++++++++++++++-- host/lib/usrp/dboard/dboards.hpp | 53 ------ host/lib/usrp/dboard_id.cpp | 34 ---- host/lib/usrp/dboard_manager.cpp | 40 ++--- 11 files changed, 307 insertions(+), 142 deletions(-) delete mode 100644 host/lib/usrp/dboard/dboards.hpp delete mode 100644 host/lib/usrp/dboard_id.cpp diff --git a/host/include/uhd/simple_device.hpp b/host/include/uhd/simple_device.hpp index 64ec85a5c..69f13a8b5 100644 --- a/host/include/uhd/simple_device.hpp +++ b/host/include/uhd/simple_device.hpp @@ -70,7 +70,7 @@ public: virtual double get_rx_rate(void) = 0; virtual std::vector get_rx_rates(void) = 0; - virtual tune_result_t set_rx_freq(double target_freq, double lo_offset) = 0; + virtual tune_result_t set_rx_freq(double freq) = 0; virtual double get_rx_freq_min(void) = 0; virtual double get_rx_freq_max(void) = 0; @@ -91,7 +91,7 @@ public: virtual double get_tx_rate(void) = 0; virtual std::vector get_tx_rates(void) = 0; - virtual tune_result_t set_tx_freq(double target_freq, double lo_offset) = 0; + virtual tune_result_t set_tx_freq(double freq) = 0; virtual double get_tx_freq_min(void) = 0; virtual double get_tx_freq_max(void) = 0; diff --git a/host/include/uhd/usrp/dboard_base.hpp b/host/include/uhd/usrp/dboard_base.hpp index b5c0d40ed..9048344ac 100644 --- a/host/include/uhd/usrp/dboard_base.hpp +++ b/host/include/uhd/usrp/dboard_base.hpp @@ -56,9 +56,9 @@ protected: dboard_id_t get_tx_id(void); private: - std::string _subdev_name; + std::string _subdev_name; dboard_interface::sptr _dboard_interface; - dboard_id_t _rx_id, _tx_id; + dboard_id_t _rx_id, _tx_id; }; /*! @@ -71,6 +71,7 @@ public: * Create a new xcvr dboard object, override in subclasses. */ xcvr_dboard_base(ctor_args_t const&); + virtual ~xcvr_dboard_base(void); }; diff --git a/host/include/uhd/usrp/dboard_id.hpp b/host/include/uhd/usrp/dboard_id.hpp index 65e3d5707..34406863d 100644 --- a/host/include/uhd/usrp/dboard_id.hpp +++ b/host/include/uhd/usrp/dboard_id.hpp @@ -16,17 +16,16 @@ // #include +#include #ifndef INCLUDED_UHD_USRP_DBOARD_ID_HPP #define INCLUDED_UHD_USRP_DBOARD_ID_HPP namespace uhd{ namespace usrp{ -enum dboard_id_t{ - ID_NONE = 0xffff, - ID_BASIC_TX = 0x0000, - ID_BASIC_RX = 0x0001 -}; +typedef uint16_t dboard_id_t; + +static const dboard_id_t ID_NONE = 0xffff; namespace dboard_id{ std::string to_string(const dboard_id_t &id); diff --git a/host/include/uhd/usrp/dboard_manager.hpp b/host/include/uhd/usrp/dboard_manager.hpp index 042947ac4..cf69675fc 100644 --- a/host/include/uhd/usrp/dboard_manager.hpp +++ b/host/include/uhd/usrp/dboard_manager.hpp @@ -44,11 +44,13 @@ public: * * \param dboard_id the dboard id (rx or tx) * \param dboard_ctor the dboard constructor function pointer + * \param name the canonical name for the dboard represented * \param subdev_names the names of the subdevs on this dboard */ static void register_subdevs( dboard_id_t dboard_id, dboard_ctor_t dboard_ctor, + const std::string &name, const prop_names_t &subdev_names ); diff --git a/host/include/uhd/utils.hpp b/host/include/uhd/utils.hpp index 25a7b5abd..e4cfd098b 100644 --- a/host/include/uhd/utils.hpp +++ b/host/include/uhd/utils.hpp @@ -23,6 +23,11 @@ #include #include +/*! + * Defines a static code block that will be called before main() + */ +#define STATIC_BLOCK(_name, _code) struct _name{_name(void){_code}} _name + /*! * Useful templated functions and classes that I like to pretend are part of stl */ diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index b141d67bb..1d2c5471b 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -30,7 +30,6 @@ SET(libuhd_sources transport/vrt.cpp usrp/dboard/basic.cpp usrp/dboard_base.cpp - usrp/dboard_id.cpp usrp/dboard_interface.cpp usrp/dboard_manager.cpp usrp/usrp2/dboard_impl.cpp diff --git a/host/lib/simple_device.cpp b/host/lib/simple_device.cpp index 63a17c52d..76f3c1262 100644 --- a/host/lib/simple_device.cpp +++ b/host/lib/simple_device.cpp @@ -179,7 +179,12 @@ public: return get_xx_rates(_rx_ddc[std::string("decims")], _rx_ddc[std::string("rate")]); } - tune_result_t set_rx_freq(double target_freq, double lo_offset){ + tune_result_t set_rx_freq(double target_freq){ + double lo_offset = 0.0; + //if the local oscillator will be in the passband, use an offset + if (wax::cast(_rx_subdev[SUBDEV_PROP_LO_INTERFERES])){ + lo_offset = get_rx_rate()*2.0; + } return tune(target_freq, lo_offset, _rx_subdev, _rx_ddc, false/* not tx */); } @@ -242,7 +247,12 @@ public: return get_xx_rates(_tx_duc[std::string("interps")], _tx_duc[std::string("rate")]); } - tune_result_t set_tx_freq(double target_freq, double lo_offset){ + tune_result_t set_tx_freq(double target_freq){ + double lo_offset = 0.0; + //if the local oscillator will be in the passband, use an offset + if (wax::cast(_tx_subdev[SUBDEV_PROP_LO_INTERFERES])){ + lo_offset = get_tx_rate()*2.0; + } return tune(target_freq, lo_offset, _tx_subdev, _tx_duc, true/* is tx */); } diff --git a/host/lib/usrp/dboard/basic.cpp b/host/lib/usrp/dboard/basic.cpp index f39ebff2f..5e245a8cf 100644 --- a/host/lib/usrp/dboard/basic.cpp +++ b/host/lib/usrp/dboard/basic.cpp @@ -15,42 +15,294 @@ // along with this program. If not, see . // -#include "dboards.hpp" +#include +#include +#include +#include +#include +#include + +using namespace uhd; +using namespace uhd::usrp; +using namespace boost::assign; /*********************************************************************** - * Basic RX dboard + * The basic and lf boards: + * They share a common class because only the frequency bounds differ. **********************************************************************/ -basic_rx::basic_rx(ctor_args_t const& args) : rx_dboard_base(args){ - /* NOP */ +class basic_rx : public rx_dboard_base{ +public: + basic_rx(ctor_args_t const& args, freq_t max_freq); + ~basic_rx(void); + + void rx_get(const wax::obj &key, wax::obj &val); + void rx_set(const wax::obj &key, const wax::obj &val); + +private: + freq_t _max_freq; +}; + +class basic_tx : public tx_dboard_base{ +public: + basic_tx(ctor_args_t const& args, freq_t max_freq); + ~basic_tx(void); + + void tx_get(const wax::obj &key, wax::obj &val); + void tx_set(const wax::obj &key, const wax::obj &val); + +private: + freq_t _max_freq; +}; + +/*********************************************************************** + * Register the basic and LF dboards + **********************************************************************/ +static dboard_base::sptr make_basic_rx(dboard_base::ctor_args_t const& args){ + return dboard_base::sptr(new basic_rx(args, 90e9)); +} + +static dboard_base::sptr make_basic_tx(dboard_base::ctor_args_t const& args){ + return dboard_base::sptr(new basic_tx(args, 90e9)); +} + +static dboard_base::sptr make_lf_rx(dboard_base::ctor_args_t const& args){ + return dboard_base::sptr(new basic_rx(args, 32e6)); +} + +static dboard_base::sptr make_lf_tx(dboard_base::ctor_args_t const& args){ + return dboard_base::sptr(new basic_tx(args, 32e6)); +} + +STATIC_BLOCK(reg_dboards, { + dboard_manager::register_subdevs(0x0000, &make_basic_tx, "Basic TX", list_of("")); + dboard_manager::register_subdevs(0x0001, &make_basic_rx, "Basic RX", list_of("a")("b")("ab")); + dboard_manager::register_subdevs(0x000e, &make_lf_tx, "LF TX", list_of("")); + dboard_manager::register_subdevs(0x000f, &make_lf_rx, "LF RX", list_of("a")("b")("ab")); +}); + +/*********************************************************************** + * Basic and LF RX dboard + **********************************************************************/ +basic_rx::basic_rx(ctor_args_t const& args, freq_t max_freq) : rx_dboard_base(args){ + _max_freq = max_freq; + // set the gpios to safe values (all inputs) + get_interface()->set_gpio_ddr(dboard_interface::GPIO_RX_BANK, 0x0000, 0xffff); } basic_rx::~basic_rx(void){ /* NOP */ } -void basic_rx::rx_get(const wax::obj &, wax::obj &){ - /* TODO */ +void basic_rx::rx_get(const wax::obj &key_, wax::obj &val){ + wax::obj key; std::string name; + boost::tie(key, name) = extract_named_prop(key_); + + //handle the get request conditioned on the key + switch(wax::cast(key)){ + case SUBDEV_PROP_NAME: + val = std::string(str(boost::format("%s:%s") + % dboard_id::to_string(get_rx_id()) + % get_subdev_name() + )); + return; + + case SUBDEV_PROP_OTHERS: + val = prop_names_t(); //empty + return; + + case SUBDEV_PROP_GAIN: + case SUBDEV_PROP_GAIN_MAX: + case SUBDEV_PROP_GAIN_MIN: + case SUBDEV_PROP_GAIN_STEP: + val = gain_t(0); + return; + + case SUBDEV_PROP_GAIN_NAMES: + val = prop_names_t(); //empty + return; + + case SUBDEV_PROP_FREQ: + val = freq_t(0); + return; + + case SUBDEV_PROP_FREQ_MAX: + val = +_max_freq; + return; + + case SUBDEV_PROP_FREQ_MIN: + val = -_max_freq; + return; + + case SUBDEV_PROP_ANTENNA: + val = std::string(""); + return; + + case SUBDEV_PROP_ANTENNA_NAMES: + val = prop_names_t(1, ""); //vector of 1 empty string + return; + + case SUBDEV_PROP_ENABLED: + val = true; //always enabled + return; + + case SUBDEV_PROP_QUADRATURE: + val = (get_subdev_name() == "ab"); //only quadrature in ab mode + return; + + case SUBDEV_PROP_IQ_SWAPPED: + case SUBDEV_PROP_SPECTRUM_INVERTED: + case SUBDEV_PROP_LO_INTERFERES: + val = false; + return; + } } -void basic_rx::rx_set(const wax::obj &, const wax::obj &){ - /* TODO */ +void basic_rx::rx_set(const wax::obj &key_, const wax::obj &val){ + wax::obj key; std::string name; + boost::tie(key, name) = extract_named_prop(key_); + + //handle the get request conditioned on the key + switch(wax::cast(key)){ + + case SUBDEV_PROP_GAIN: + ASSERT_THROW(wax::cast(val) == gain_t(0)); + return; + + case SUBDEV_PROP_ANTENNA: + ASSERT_THROW(wax::cast(val) == std::string("")); + return; + + case SUBDEV_PROP_ENABLED: + return; // it wont do you much good, but you can set it + + case SUBDEV_PROP_NAME: + case SUBDEV_PROP_OTHERS: + case SUBDEV_PROP_GAIN_MAX: + case SUBDEV_PROP_GAIN_MIN: + case SUBDEV_PROP_GAIN_STEP: + case SUBDEV_PROP_GAIN_NAMES: + case SUBDEV_PROP_FREQ: + case SUBDEV_PROP_FREQ_MAX: + case SUBDEV_PROP_FREQ_MIN: + case SUBDEV_PROP_ANTENNA_NAMES: + case SUBDEV_PROP_QUADRATURE: + case SUBDEV_PROP_IQ_SWAPPED: + case SUBDEV_PROP_SPECTRUM_INVERTED: + case SUBDEV_PROP_LO_INTERFERES: + throw std::runtime_error(str(boost::format( + "Error: trying to set read-only property on %s subdev" + ) % dboard_id::to_string(get_rx_id()))); + } } /*********************************************************************** - * Basic TX dboard + * Basic and LF TX dboard **********************************************************************/ -basic_tx::basic_tx(ctor_args_t const& args) : tx_dboard_base(args){ - /* NOP */ +basic_tx::basic_tx(ctor_args_t const& args, freq_t max_freq) : tx_dboard_base(args){ + _max_freq = max_freq; + // set the gpios to safe values (all inputs) + get_interface()->set_gpio_ddr(dboard_interface::GPIO_TX_BANK, 0x0000, 0xffff); } basic_tx::~basic_tx(void){ /* NOP */ } -void basic_tx::tx_get(const wax::obj &, wax::obj &){ - /* TODO */ +void basic_tx::tx_get(const wax::obj &key_, wax::obj &val){ + wax::obj key; std::string name; + boost::tie(key, name) = extract_named_prop(key_); + + //handle the get request conditioned on the key + switch(wax::cast(key)){ + case SUBDEV_PROP_NAME: + val = dboard_id::to_string(get_tx_id()); + return; + + case SUBDEV_PROP_OTHERS: + val = prop_names_t(); //empty + return; + + case SUBDEV_PROP_GAIN: + case SUBDEV_PROP_GAIN_MAX: + case SUBDEV_PROP_GAIN_MIN: + case SUBDEV_PROP_GAIN_STEP: + val = gain_t(0); + return; + + case SUBDEV_PROP_GAIN_NAMES: + val = prop_names_t(); //empty + return; + + case SUBDEV_PROP_FREQ: + val = freq_t(0); + return; + + case SUBDEV_PROP_FREQ_MAX: + val = +_max_freq; + return; + + case SUBDEV_PROP_FREQ_MIN: + val = -_max_freq; + return; + + case SUBDEV_PROP_ANTENNA: + val = std::string(""); + return; + + case SUBDEV_PROP_ANTENNA_NAMES: + val = prop_names_t(1, ""); //vector of 1 empty string + return; + + case SUBDEV_PROP_ENABLED: + val = true; //always enabled + return; + + case SUBDEV_PROP_QUADRATURE: + val = true; + return; + + case SUBDEV_PROP_IQ_SWAPPED: + case SUBDEV_PROP_SPECTRUM_INVERTED: + case SUBDEV_PROP_LO_INTERFERES: + val = false; + return; + } } -void basic_tx::tx_set(const wax::obj &, const wax::obj &){ - /* TODO */ +void basic_tx::tx_set(const wax::obj &key_, const wax::obj &val){ + wax::obj key; std::string name; + boost::tie(key, name) = extract_named_prop(key_); + + //handle the get request conditioned on the key + switch(wax::cast(key)){ + + case SUBDEV_PROP_GAIN: + ASSERT_THROW(wax::cast(val) == gain_t(0)); + return; + + case SUBDEV_PROP_ANTENNA: + ASSERT_THROW(wax::cast(val) == std::string("")); + return; + + case SUBDEV_PROP_ENABLED: + return; // it wont do you much good, but you can set it + + case SUBDEV_PROP_NAME: + case SUBDEV_PROP_OTHERS: + case SUBDEV_PROP_GAIN_MAX: + case SUBDEV_PROP_GAIN_MIN: + case SUBDEV_PROP_GAIN_STEP: + case SUBDEV_PROP_GAIN_NAMES: + case SUBDEV_PROP_FREQ: + case SUBDEV_PROP_FREQ_MAX: + case SUBDEV_PROP_FREQ_MIN: + case SUBDEV_PROP_ANTENNA_NAMES: + case SUBDEV_PROP_QUADRATURE: + case SUBDEV_PROP_IQ_SWAPPED: + case SUBDEV_PROP_SPECTRUM_INVERTED: + case SUBDEV_PROP_LO_INTERFERES: + throw std::runtime_error(str(boost::format( + "Error: trying to set read-only property on %s subdev" + ) % dboard_id::to_string(get_tx_id()))); + } } diff --git a/host/lib/usrp/dboard/dboards.hpp b/host/lib/usrp/dboard/dboards.hpp deleted file mode 100644 index 79b90d593..000000000 --- a/host/lib/usrp/dboard/dboards.hpp +++ /dev/null @@ -1,53 +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_LOCAL_DBOARDS_HPP -#define INCLUDED_LOCAL_DBOARDS_HPP - -#include - -using namespace uhd::usrp; - -/*********************************************************************** - * The basic boards: - **********************************************************************/ -class basic_rx : public rx_dboard_base{ -public: - static dboard_base::sptr make(ctor_args_t const& args){ - return dboard_base::sptr(new basic_rx(args)); - } - basic_rx(ctor_args_t const& args); - ~basic_rx(void); - - void rx_get(const wax::obj &key, wax::obj &val); - void rx_set(const wax::obj &key, const wax::obj &val); -}; - -class basic_tx : public tx_dboard_base{ -public: - static dboard_base::sptr make(ctor_args_t const& args){ - return dboard_base::sptr(new basic_tx(args)); - } - basic_tx(ctor_args_t const& args); - ~basic_tx(void); - - void tx_get(const wax::obj &key, wax::obj &val); - void tx_set(const wax::obj &key, const wax::obj &val); - -}; - -#endif /* INCLUDED_LOCAL_DBOARDS_HPP */ diff --git a/host/lib/usrp/dboard_id.cpp b/host/lib/usrp/dboard_id.cpp deleted file mode 100644 index d2ef7cd7d..000000000 --- a/host/lib/usrp/dboard_id.cpp +++ /dev/null @@ -1,34 +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 -#include -#include - -using namespace uhd::usrp; - -std::string dboard_id::to_string(const dboard_id_t &id){ - //map the dboard ids to string representations - uhd::dict id_to_str; - id_to_str[ID_NONE] = "none"; - id_to_str[ID_BASIC_TX] = "basic tx"; - id_to_str[ID_BASIC_RX] = "basic rx"; - - //get the string representation - std::string name = (id_to_str.has_key(id))? id_to_str[id] : "unknown"; - return str(boost::format("%s (0x%.4x)") % name % id); -} diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp index cce239f3e..57b449175 100644 --- a/host/lib/usrp/dboard_manager.cpp +++ b/host/lib/usrp/dboard_manager.cpp @@ -18,36 +18,12 @@ #include #include #include -#include #include #include #include -#include "dboard/dboards.hpp" using namespace uhd; using namespace uhd::usrp; -using namespace boost::assign; - -/*********************************************************************** - * register internal dboards - * - * Register internal/known dboards located in this build tree. - * Each board should have entries below mapping an id to a constructor. - * The xcvr type boards should register both rx and tx sides. - * - * This function will be called before new boards are registered. - * This allows for internal boards to be externally overridden. - * This function will also be called when creating a new dboard_manager - * to ensure that the maps are filled with the entries below. - **********************************************************************/ -static void register_internal_dboards(void){ - //ensure that this function can only be called once per instance - static bool called = false; - if (called) return; called = true; - //register the known dboards (dboard id, constructor, subdev names) - dboard_manager::register_subdevs(ID_BASIC_TX, &basic_tx::make, list_of("")); - dboard_manager::register_subdevs(ID_BASIC_RX, &basic_rx::make, list_of("a")("b")("ab")); -} /*********************************************************************** * storage and registering for dboards @@ -57,15 +33,24 @@ typedef boost::tuple args_t; //map a dboard id to a dboard constructor static uhd::dict id_to_args_map; +//map a dboard id to a canonical name +static uhd::dict id_to_str; + void dboard_manager::register_subdevs( dboard_id_t dboard_id, dboard_ctor_t dboard_ctor, + const std::string &name, const prop_names_t &subdev_names ){ - register_internal_dboards(); //always call first + id_to_str[dboard_id] = name; id_to_args_map[dboard_id] = args_t(dboard_ctor, subdev_names); } +std::string dboard_id::to_string(const dboard_id_t &id){ + std::string name = (id_to_str.has_key(id))? id_to_str[id] : "unknown"; + return str(boost::format("%s (0x%.4x)") % name % id); +} + /*********************************************************************** * dboard manager implementation class **********************************************************************/ @@ -160,12 +145,12 @@ static args_t get_dboard_args( ){ //special case, its rx and the none id (0xffff) if (xx_type == "rx" and dboard_id == ID_NONE){ - return args_t(&basic_rx::make, list_of("ab")); + return get_dboard_args(0x0001, xx_type); } //special case, its tx and the none id (0xffff) if (xx_type == "tx" and dboard_id == ID_NONE){ - return args_t(&basic_tx::make, list_of("")); + return get_dboard_args(0x0000, xx_type); } //verify that there is a registered constructor for this id @@ -185,7 +170,6 @@ dboard_manager_impl::dboard_manager_impl( dboard_id_t tx_dboard_id, dboard_interface::sptr interface ){ - register_internal_dboards(); //always call first _interface = interface; dboard_ctor_t rx_dboard_ctor; prop_names_t rx_subdevs; -- cgit v1.2.3 From daed43a8a873ad5cc16ac8a3eb6db5a8fe126fa5 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 11 Mar 2010 18:37:34 -0800 Subject: Cleaned up the gain handler (thing that gets and sets wildcard gains) and made use of it in the dboard manager so it intercepts the sets and gets. While doing this, fixed something with nested links in wax obj. Added some useful macros and templates to the utils. --- host/include/uhd/gain_handler.hpp | 68 +++++----- host/include/uhd/utils.hpp | 7 +- host/lib/device.cpp | 15 ++- host/lib/gain_handler.cpp | 264 ++++++++++++++++++++++---------------- host/lib/usrp/dboard/basic.cpp | 4 +- host/lib/usrp/dboard_manager.cpp | 83 +++++++----- host/lib/wax.cpp | 10 +- host/test/gain_handler_test.cpp | 18 ++- 8 files changed, 271 insertions(+), 198 deletions(-) diff --git a/host/include/uhd/gain_handler.hpp b/host/include/uhd/gain_handler.hpp index 06800315a..fade86f53 100644 --- a/host/include/uhd/gain_handler.hpp +++ b/host/include/uhd/gain_handler.hpp @@ -15,11 +15,9 @@ // along with this program. If not, see . // -#include #include -#include +#include #include -#include #ifndef INCLUDED_UHD_GAIN_HANDLER_HPP #define INCLUDED_UHD_GAIN_HANDLER_HPP @@ -29,29 +27,41 @@ namespace uhd{ class gain_handler{ public: typedef boost::shared_ptr sptr; + typedef boost::function is_equal_t; - template gain_handler( - wax::obj *wax_obj_ptr, const T &gain_prop, - const T &gain_min_prop, const T &gain_max_prop, - const T &gain_step_prop, const T &gain_names_prop - ){ - _wax_obj_ptr = wax_obj_ptr; - _gain_prop = gain_prop; - _gain_min_prop = gain_min_prop; - _gain_max_prop = gain_max_prop; - _gain_step_prop = gain_step_prop; - _gain_names_prop = gain_names_prop; - _is_equal = boost::bind(&gain_handler::is_equal, _1, _2); - } + /*! + * A set of properties for dealing with gains. + */ + struct gain_props_t{ + wax::obj gain_val_prop; + wax::obj gain_min_prop; + wax::obj gain_max_prop; + wax::obj gain_step_prop; + wax::obj gain_names_prop; + gain_props_t(void); //default constructor + }; - ~gain_handler(void); + /*! + * Make a new gain handler. + * The construction arguments are agnostic to the property type. + * It is up to the caller to provide an "is_equal" function that + * can tell weather two properties (in a wax obj) are equal. + * \param link a link to the wax obj with properties + * \param gain_props a struct of properties keys + * \param is_equal the function that tests for equal properties + */ + static sptr make( + const wax::obj &link, + const gain_props_t &gain_props, + is_equal_t is_equal + ); /*! * Intercept gets for overall gain, min, max, step. * Ensures that the gain name is valid. * \return true for handled, false to pass on */ - bool intercept_get(const wax::obj &key, wax::obj &val); + virtual bool intercept_get(const wax::obj &key, wax::obj &val) = 0; /*! * Intercept sets for overall gain. @@ -59,27 +69,10 @@ public: * Ensures that the new gain is within range. * \return true for handled, false to pass on */ - bool intercept_set(const wax::obj &key, const wax::obj &val); - -private: - - wax::obj *_wax_obj_ptr; - wax::obj _gain_prop; - wax::obj _gain_min_prop; - wax::obj _gain_max_prop; - wax::obj _gain_step_prop; - wax::obj _gain_names_prop; + virtual bool intercept_set(const wax::obj &key, const wax::obj &val) = 0; /*! - * Verify that the key is valid: - * If its a named prop for gain, ensure that name is valid. - * If the name if not valid, throw a std::invalid_argument. - * The name can only be valid if its in the list of gain names. - */ - void _check_key(const wax::obj &key); - - /* - * Private interface to test if two wax types are equal: + * Function template to test if two wax types are equal: * The constructor will bind an instance of this for a specific type. * This bound equals functions allows the intercept methods to be non-templated. */ @@ -91,7 +84,6 @@ private: return false; } } - boost::function _is_equal; }; diff --git a/host/include/uhd/utils.hpp b/host/include/uhd/utils.hpp index e4cfd098b..5d6a18b3a 100644 --- a/host/include/uhd/utils.hpp +++ b/host/include/uhd/utils.hpp @@ -26,7 +26,7 @@ /*! * Defines a static code block that will be called before main() */ -#define STATIC_BLOCK(_name, _code) struct _name{_name(void){_code}} _name +#define STATIC_BLOCK(_x) struct _x{_x();}_x;_x::_x() /*! * Useful templated functions and classes that I like to pretend are part of stl @@ -55,6 +55,11 @@ namespace std{ return tmp; } + template + T reduce(Iterable iterable, Function fcn, T init = 0){ + return reduce(iterable.begin(), iterable.end(), fcn, init); + } + template bool has(InputIterator first, InputIterator last, const T &elem){ return last != std::find(first, last, elem); diff --git a/host/lib/device.cpp b/host/lib/device.cpp index 82052708a..4b64e4a15 100644 --- a/host/lib/device.cpp +++ b/host/lib/device.cpp @@ -32,9 +32,16 @@ using namespace uhd; * Create a new device from a device address. * Based on the address, call the appropriate make functions. * \param dev_addr the device address + * \param hint the device address that was used to find the device * \return a smart pointer to a device */ -static device::sptr make_device(const device_addr_t &dev_addr){ +static device::sptr make_device(const device_addr_t &dev_addr_, const device_addr_t &hint){ + //copy keys that were in hint but not in dev_addr + //this way, we can pass additional transport arguments + device_addr_t dev_addr = dev_addr_; + BOOST_FOREACH(std::string key, hint.get_keys()){ + if (not dev_addr.has_key(key)) dev_addr[key] = hint[key]; + } //create a usrp1e if (dev_addr["type"] == "usrp1e"){ @@ -46,7 +53,9 @@ static device::sptr make_device(const device_addr_t &dev_addr){ return usrp::usrp2::make(dev_addr); } - throw std::runtime_error("cant make a device"); + throw std::runtime_error(str( + boost::format("Cant make a device for %s") % device_addr::to_string(dev_addr) + )); } /*! @@ -126,7 +135,7 @@ device::sptr device::make(const device_addr_t &hint, size_t which){ } //create and register a new device catch(const std::assert_error &e){ - device::sptr dev = make_device(dev_addr); + device::sptr dev = make_device(dev_addr, hint); hash_to_device[dev_hash] = dev; return dev; } diff --git a/host/lib/gain_handler.cpp b/host/lib/gain_handler.cpp index b03d5bda2..8f840ae7f 100644 --- a/host/lib/gain_handler.cpp +++ b/host/lib/gain_handler.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -25,143 +26,178 @@ using namespace uhd; /*********************************************************************** - * Helper functions and macros + * helper functions **********************************************************************/ -#define GET_PROP_NAMES() \ - wax::cast((*_wax_obj_ptr)[_gain_names_prop]) - -/*! - * Helper function to simplify getting a named gain (also min, max, step). - */ -static gain_t get_named_gain(wax::obj *wax_obj_ptr, wax::obj prop, std::string name){ - return wax::cast((*wax_obj_ptr)[named_prop_t(prop, name)]); +static gain_t gain_max(gain_t a, gain_t b){ + return std::max(a, b); +} +static gain_t gain_sum(gain_t a, gain_t b){ + return std::sum(a, b); +} + +/*********************************************************************** + * gain handler implementation interface + **********************************************************************/ +class gain_handler_impl : public gain_handler{ +public: + gain_handler_impl( + const wax::obj &link, + const gain_props_t &gain_props, + is_equal_t is_equal + ); + ~gain_handler_impl(void); + bool intercept_get(const wax::obj &key, wax::obj &val); + bool intercept_set(const wax::obj &key, const wax::obj &val); + +private: + wax::obj _link; + gain_props_t _gain_props; + is_equal_t _is_equal; + + prop_names_t get_gain_names(void); + std::vector get_gains(const wax::obj &prop_key); + gain_t get_overall_gain_val(void); + gain_t get_overall_gain_min(void); + gain_t get_overall_gain_max(void); + gain_t get_overall_gain_step(void); +}; + +/*********************************************************************** + * the make function + **********************************************************************/ +gain_handler::sptr gain_handler::make( + const wax::obj &link, + const gain_props_t &gain_props, + is_equal_t is_equal +){ + return sptr(new gain_handler_impl(link, gain_props, is_equal)); } /*********************************************************************** - * Class methods of gain handler + * gain handler implementation methods **********************************************************************/ -gain_handler::~gain_handler(void){ +gain_handler::gain_props_t::gain_props_t(void){ /* NOP */ } -void gain_handler::_check_key(const wax::obj &key_){ - wax::obj key; std::string name; - boost::tie(key, name) = extract_named_prop(key_); - - try{ - //only handle non wildcard names - ASSERT_THROW(name != ""); - - //only handle these gain props - ASSERT_THROW( - _is_equal(key, _gain_prop) or - _is_equal(key, _gain_min_prop) or - _is_equal(key, _gain_max_prop) or - _is_equal(key, _gain_step_prop) - ); - - //check that the name is allowed - prop_names_t prop_names = GET_PROP_NAMES(); - ASSERT_THROW(not std::has(prop_names.begin(), prop_names.end(), name)); - - //if we get here, throw an exception - throw std::invalid_argument(str( - boost::format("Unknown gain name %s") % name - )); - } - catch(const std::assert_error &){} +gain_handler_impl::gain_handler_impl( + const wax::obj &link, + const gain_props_t &gain_props, + is_equal_t is_equal +){ + _link = link; + _gain_props = gain_props; + _is_equal = is_equal; } -static gain_t gain_max(gain_t a, gain_t b){ - return std::max(a, b); +gain_handler_impl::~gain_handler_impl(void){ + /* NOP */ } -static gain_t gain_sum(gain_t a, gain_t b){ - return std::sum(a, b); + +prop_names_t gain_handler_impl::get_gain_names(void){ + return wax::cast(_link[_gain_props.gain_names_prop]); } -bool gain_handler::intercept_get(const wax::obj &key, wax::obj &val){ - _check_key(key); //verify the key - - std::vector gain_props = boost::assign::list_of - (_gain_prop)(_gain_min_prop)(_gain_max_prop)(_gain_step_prop); - - /*! - * Handle getting overall gains when a name is not specified. - * For the gain props below, set the overall value and return true. - */ - BOOST_FOREACH(wax::obj prop_key, gain_props){ - if (_is_equal(key, prop_key)){ - //form the gains vector from the props vector - prop_names_t prop_names = GET_PROP_NAMES(); - std::vector gains(prop_names.size()); - std::transform( - prop_names.begin(), prop_names.end(), gains.begin(), - boost::bind(get_named_gain, _wax_obj_ptr, key, _1) - ); - - //reduce across the gain vector - if (_is_equal(key, _gain_step_prop)){ - val = std::reduce(gains.begin(), gains.end(), gain_max); - } - else{ - val = std::reduce(gains.begin(), gains.end(), gain_sum); - } - return true; - } +std::vector gain_handler_impl::get_gains(const wax::obj &prop_key){ + std::vector gains; + BOOST_FOREACH(std::string name, get_gain_names()){ + gains.push_back(wax::cast(_link[named_prop_t(prop_key, name)])); } + return gains; +} + +gain_t gain_handler_impl::get_overall_gain_val(void){ + return std::reduce(get_gains(_gain_props.gain_val_prop), gain_sum); +} - return false; +gain_t gain_handler_impl::get_overall_gain_min(void){ + return std::reduce(get_gains(_gain_props.gain_min_prop), gain_sum); } -bool gain_handler::intercept_set(const wax::obj &key_, const wax::obj &val){ - _check_key(key_); //verify the key +gain_t gain_handler_impl::get_overall_gain_max(void){ + return std::reduce(get_gains(_gain_props.gain_max_prop), gain_sum); +} + +gain_t gain_handler_impl::get_overall_gain_step(void){ + return std::reduce(get_gains(_gain_props.gain_step_prop), gain_max); +} +/*********************************************************************** + * gain handler implementation get method + **********************************************************************/ +bool gain_handler_impl::intercept_get(const wax::obj &key_, wax::obj &val){ wax::obj key; std::string name; boost::tie(key, name) = extract_named_prop(key_); - /*! - * Verify that a named gain component is in range. - */ - try{ - //only handle the gain props - ASSERT_THROW(_is_equal(key, _gain_prop)); - - //check that the gain is in range - gain_t gain = wax::cast(val); - gain_t gain_min = get_named_gain(_wax_obj_ptr, _gain_min_prop, name); - gain_t gain_max = get_named_gain(_wax_obj_ptr, _gain_max_prop, name); - ASSERT_THROW(gain > gain_max or gain < gain_min); - - //if we get here, throw an exception - throw std::range_error(str( - boost::format("gain %s is out of range of (%f, %f)") % name % gain_min % gain_max - )); + //not a wildcard... dont handle (but check name) + if (name != ""){ + assert_has(get_gain_names(), name, "gain name"); + return false; + } + + if (_is_equal(key, _gain_props.gain_val_prop)){ + val = get_overall_gain_val(); + return true; + } + + if (_is_equal(key, _gain_props.gain_min_prop)){ + val = get_overall_gain_min(); + return true; } - catch(const std::assert_error &){} - - /*! - * Handle setting the overall gain. - */ - if (_is_equal(key, _gain_prop) and name == ""){ - gain_t gain = wax::cast(val); - prop_names_t prop_names = GET_PROP_NAMES(); - BOOST_FOREACH(std::string name, prop_names){ - //get the min, max, step for this gain name - gain_t gain_min = get_named_gain(_wax_obj_ptr, _gain_min_prop, name); - gain_t gain_max = get_named_gain(_wax_obj_ptr, _gain_max_prop, name); - gain_t gain_step = get_named_gain(_wax_obj_ptr, _gain_step_prop, name); - - //clip g to be within the allowed range - gain_t g = std::min(std::max(gain, gain_min), gain_max); - //set g to be a multiple of the step size - g -= fmod(g, gain_step); - //set g to be the new gain - (*_wax_obj_ptr)[named_prop_t(_gain_prop, name)] = g; - //subtract g out of the total gain left to apply - gain -= g; - } + + if (_is_equal(key, _gain_props.gain_max_prop)){ + val = get_overall_gain_max(); return true; } - return false; + if (_is_equal(key, _gain_props.gain_step_prop)){ + val = get_overall_gain_step(); + return true; + } + + return false; //not handled +} + +/*********************************************************************** + * gain handler implementation set method + **********************************************************************/ +bool gain_handler_impl::intercept_set(const wax::obj &key_, const wax::obj &val){ + wax::obj key; std::string name; + boost::tie(key, name) = extract_named_prop(key_); + + //not a gain value key... dont handle + if (not _is_equal(key, _gain_props.gain_val_prop)) return false; + + gain_t gain_val = wax::cast(val); + + //not a wildcard... dont handle (but check name and range) + if (name != ""){ + assert_has(get_gain_names(), name, "gain name"); + gain_t gain_min = wax::cast(_link[named_prop_t(_gain_props.gain_min_prop, name)]); + gain_t gain_max = wax::cast(_link[named_prop_t(_gain_props.gain_max_prop, name)]); + if (gain_val > gain_max or gain_val < gain_min) throw std::range_error(str( + boost::format("A value of %f for gain %s is out of range of (%f, %f)") + % gain_val % name % gain_min % gain_max + )); + return false; + } + + //set the overall gain + BOOST_FOREACH(std::string name, get_gain_names()){ + //get the min, max, step for this gain name + gain_t gain_min = wax::cast(_link[named_prop_t(_gain_props.gain_min_prop, name)]); + gain_t gain_max = wax::cast(_link[named_prop_t(_gain_props.gain_max_prop, name)]); + gain_t gain_step = wax::cast(_link[named_prop_t(_gain_props.gain_step_prop, name)]); + + //clip g to be within the allowed range + gain_t g = std::min(std::max(gain_val, gain_min), gain_max); + //set g to be a multiple of the step size + g -= fmod(g, gain_step); + //set g to be the new gain + _link[named_prop_t(_gain_props.gain_val_prop, name)] = g; + //subtract g out of the total gain left to apply + gain_val -= g; + } + + return true; } diff --git a/host/lib/usrp/dboard/basic.cpp b/host/lib/usrp/dboard/basic.cpp index 5e245a8cf..4b74e4a47 100644 --- a/host/lib/usrp/dboard/basic.cpp +++ b/host/lib/usrp/dboard/basic.cpp @@ -73,12 +73,12 @@ static dboard_base::sptr make_lf_tx(dboard_base::ctor_args_t const& args){ return dboard_base::sptr(new basic_tx(args, 32e6)); } -STATIC_BLOCK(reg_dboards, { +STATIC_BLOCK(reg_dboards){ dboard_manager::register_subdevs(0x0000, &make_basic_tx, "Basic TX", list_of("")); dboard_manager::register_subdevs(0x0001, &make_basic_rx, "Basic RX", list_of("a")("b")("ab")); dboard_manager::register_subdevs(0x000e, &make_lf_tx, "LF TX", list_of("")); dboard_manager::register_subdevs(0x000f, &make_lf_rx, "LF RX", list_of("a")("b")("ab")); -}); +} /*********************************************************************** * Basic and LF RX dboard diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp index 57b449175..08b92e62a 100644 --- a/host/lib/usrp/dboard_manager.cpp +++ b/host/lib/usrp/dboard_manager.cpp @@ -16,10 +16,12 @@ // #include +#include #include #include #include #include +#include #include using namespace uhd; @@ -42,6 +44,7 @@ void dboard_manager::register_subdevs( const std::string &name, const prop_names_t &subdev_names ){ + //std::cout << "registering: " << name << std::endl; id_to_str[dboard_id] = name; id_to_args_map[dboard_id] = args_t(dboard_ctor, subdev_names); } @@ -52,36 +55,7 @@ std::string dboard_id::to_string(const dboard_id_t &id){ } /*********************************************************************** - * dboard manager implementation class - **********************************************************************/ -class dboard_manager_impl : public dboard_manager{ - -public: - dboard_manager_impl( - dboard_id_t rx_dboard_id, - dboard_id_t tx_dboard_id, - dboard_interface::sptr interface - ); - ~dboard_manager_impl(void); - - //dboard_interface - prop_names_t get_rx_subdev_names(void); - prop_names_t get_tx_subdev_names(void); - wax::obj get_rx_subdev(const std::string &subdev_name); - wax::obj get_tx_subdev(const std::string &subdev_name); - -private: - //list of rx and tx dboards in this dboard_manager - //each dboard here is actually a subdevice proxy - //the subdevice proxy is internal to the cpp file - uhd::dict _rx_dboards; - uhd::dict _tx_dboards; - dboard_interface::sptr _interface; - void set_nice_gpio_pins(void); -}; - -/*********************************************************************** - * internal helper classes + * internal helper classe **********************************************************************/ /*! * A special wax proxy object that forwards calls to a subdev. @@ -95,7 +69,18 @@ public: //structors subdev_proxy(dboard_base::sptr subdev, type_t type) : _subdev(subdev), _type(type){ - /* NOP */ + //initialize gain props struct + gain_handler::gain_props_t gain_props; + gain_props.gain_val_prop = SUBDEV_PROP_GAIN; + gain_props.gain_min_prop = SUBDEV_PROP_GAIN_MIN; + gain_props.gain_max_prop = SUBDEV_PROP_GAIN_MAX; + gain_props.gain_step_prop = SUBDEV_PROP_GAIN_STEP; + gain_props.gain_names_prop = SUBDEV_PROP_GAIN_NAMES; + + //make a new gain handler + _gain_handler = gain_handler::make( + this->get_link(), gain_props, boost::bind(&gain_handler::is_equal, _1, _2) + ); } ~subdev_proxy(void){ @@ -103,11 +88,13 @@ public: } private: + gain_handler::sptr _gain_handler; dboard_base::sptr _subdev; type_t _type; //forward the get calls to the rx or tx void get(const wax::obj &key, wax::obj &val){ + if (_gain_handler->intercept_get(key, val)) return; switch(_type){ case RX_TYPE: return _subdev->rx_get(key, val); case TX_TYPE: return _subdev->tx_get(key, val); @@ -116,6 +103,7 @@ private: //forward the set calls to the rx or tx void set(const wax::obj &key, const wax::obj &val){ + if (_gain_handler->intercept_set(key, val)) return; switch(_type){ case RX_TYPE: return _subdev->rx_set(key, val); case TX_TYPE: return _subdev->tx_set(key, val); @@ -123,6 +111,35 @@ private: } }; +/*********************************************************************** + * dboard manager implementation class + **********************************************************************/ +class dboard_manager_impl : public dboard_manager{ + +public: + dboard_manager_impl( + dboard_id_t rx_dboard_id, + dboard_id_t tx_dboard_id, + dboard_interface::sptr interface + ); + ~dboard_manager_impl(void); + + //dboard_interface + prop_names_t get_rx_subdev_names(void); + prop_names_t get_tx_subdev_names(void); + wax::obj get_rx_subdev(const std::string &subdev_name); + wax::obj get_tx_subdev(const std::string &subdev_name); + +private: + //list of rx and tx dboards in this dboard_manager + //each dboard here is actually a subdevice proxy + //the subdevice proxy is internal to the cpp file + uhd::dict _rx_dboards; + uhd::dict _tx_dboards; + dboard_interface::sptr _interface; + void set_nice_gpio_pins(void); +}; + /*********************************************************************** * make routine for dboard manager **********************************************************************/ @@ -241,7 +258,7 @@ wax::obj dboard_manager_impl::get_rx_subdev(const std::string &subdev_name){ str(boost::format("Unknown rx subdev name %s") % subdev_name) ); //get a link to the rx subdev proxy - return wax::cast(_rx_dboards[subdev_name])->get_link(); + return _rx_dboards[subdev_name]->get_link(); } wax::obj dboard_manager_impl::get_tx_subdev(const std::string &subdev_name){ @@ -249,7 +266,7 @@ wax::obj dboard_manager_impl::get_tx_subdev(const std::string &subdev_name){ str(boost::format("Unknown tx subdev name %s") % subdev_name) ); //get a link to the tx subdev proxy - return wax::cast(_tx_dboards[subdev_name])->get_link(); + return _tx_dboards[subdev_name]->get_link(); } void dboard_manager_impl::set_nice_gpio_pins(void){ diff --git a/host/lib/wax.cpp b/host/lib/wax.cpp index c08398c50..0348d9a66 100644 --- a/host/lib/wax.cpp +++ b/host/lib/wax.cpp @@ -36,7 +36,11 @@ public: link_args_t(const wax::obj *obj_ptr) : _obj_ptr(obj_ptr){ /* NOP */ } - wax::obj & operator()(void){ + wax::obj & operator()(void) const{ + //recursively resolve link args to get at original pointer + if (_obj_ptr->type() == typeid(link_args_t)){ + return wax::cast(*_obj_ptr)(); + } return *const_cast(_obj_ptr); } private: @@ -56,10 +60,10 @@ public: proxy_args_t(const wax::obj *obj_ptr, const wax::obj &key) : _key(key){ _obj_link = obj_ptr->get_link(); } - wax::obj & operator()(void){ + wax::obj & operator()(void) const{ return wax::cast(_obj_link)(); } - const wax::obj & key(void){ + const wax::obj & key(void) const{ return _key; } private: diff --git a/host/test/gain_handler_test.cpp b/host/test/gain_handler_test.cpp index c81221aac..9a6a50dab 100644 --- a/host/test/gain_handler_test.cpp +++ b/host/test/gain_handler_test.cpp @@ -17,7 +17,9 @@ #include #include +#include #include +#include #include using namespace uhd; @@ -33,9 +35,17 @@ enum prop_t{ class gainful_obj : public wax::obj{ public: gainful_obj(void){ - _gain_handler = gain_handler::sptr(new gain_handler( - this, PROP_GAIN, PROP_GAIN_MIN, PROP_GAIN_MAX, PROP_GAIN_STEP, PROP_GAIN_NAMES - )); + //initialize gain props struct + gain_handler::gain_props_t gain_props; + gain_props.gain_val_prop = PROP_GAIN; + gain_props.gain_min_prop = PROP_GAIN_MIN; + gain_props.gain_max_prop = PROP_GAIN_MAX; + gain_props.gain_step_prop = PROP_GAIN_STEP; + gain_props.gain_names_prop = PROP_GAIN_NAMES; + //make a new gain handler + _gain_handler = gain_handler::make( + this->get_link(), gain_props, boost::bind(&gain_handler::is_equal, _1, _2) + ); _gains["g0"] = 0; _gains["g1"] = 0; _gains_min["g0"] = -10; @@ -113,7 +123,7 @@ BOOST_AUTO_TEST_CASE(test_gain_handler){ BOOST_CHECK_THROW( wax::cast(go0[named_prop_t(PROP_GAIN, "fail")]), - std::invalid_argument + std::exception ); std::cout << "verifying the overall min, max, step" << std::endl; -- cgit v1.2.3 From 2147c5f61c2eb6ef1a68419d7b1041a54cbb14a2 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 12 Mar 2010 16:01:01 -0800 Subject: Removed freq min and max and gain min, max, and step... replaced it with gain and freq range tuples. This simplifies the api calls and subdev properties. --- host/include/uhd/gain_handler.hpp | 14 ++---- host/include/uhd/props.hpp | 13 +++-- host/include/uhd/simple_device.hpp | 14 ++---- host/include/uhd/utils.hpp | 5 -- host/lib/gain_handler.cpp | 98 +++++++++++++++----------------------- host/lib/simple_device.cpp | 56 +++++++++------------- host/lib/usrp/dboard/basic.cpp | 44 +++++++---------- host/lib/usrp/dboard_manager.cpp | 13 +++-- host/test/gain_handler_test.cpp | 80 +++++++++++++------------------ 9 files changed, 131 insertions(+), 206 deletions(-) diff --git a/host/include/uhd/gain_handler.hpp b/host/include/uhd/gain_handler.hpp index fade86f53..2d3f8a3f4 100644 --- a/host/include/uhd/gain_handler.hpp +++ b/host/include/uhd/gain_handler.hpp @@ -32,13 +32,9 @@ public: /*! * A set of properties for dealing with gains. */ - struct gain_props_t{ - wax::obj gain_val_prop; - wax::obj gain_min_prop; - wax::obj gain_max_prop; - wax::obj gain_step_prop; - wax::obj gain_names_prop; - gain_props_t(void); //default constructor + struct props_t{ + wax::obj value, range, names; + props_t(void); //default constructor }; /*! @@ -47,12 +43,12 @@ public: * It is up to the caller to provide an "is_equal" function that * can tell weather two properties (in a wax obj) are equal. * \param link a link to the wax obj with properties - * \param gain_props a struct of properties keys + * \param props a struct of properties keys * \param is_equal the function that tests for equal properties */ static sptr make( const wax::obj &link, - const gain_props_t &gain_props, + const props_t &props, is_equal_t is_equal ); diff --git a/host/include/uhd/props.hpp b/host/include/uhd/props.hpp index dea2baf52..f2ba1769f 100644 --- a/host/include/uhd/props.hpp +++ b/host/include/uhd/props.hpp @@ -30,6 +30,12 @@ namespace uhd{ typedef float gain_t; typedef double freq_t; + //gain range tuple (min, max, step) + typedef boost::tuple gain_range_t; + + //freq range tuple (min, max) + typedef boost::tuple freq_range_t; + //scalar types (have not used yet, dont uncomment until needed) //typedef int int_scalar_t; //typedef float real_scalar_t; @@ -143,13 +149,10 @@ namespace uhd{ SUBDEV_PROP_NAME, //ro, std::string SUBDEV_PROP_OTHERS, //ro, prop_names_t SUBDEV_PROP_GAIN, //rw, gain_t - SUBDEV_PROP_GAIN_MAX, //ro, gain_t - SUBDEV_PROP_GAIN_MIN, //ro, gain_t - SUBDEV_PROP_GAIN_STEP, //ro, gain_t + SUBDEV_PROP_GAIN_RANGE, //ro, gain_range_t SUBDEV_PROP_GAIN_NAMES, //ro, prop_names_t SUBDEV_PROP_FREQ, //rw, freq_t - SUBDEV_PROP_FREQ_MAX, //ro, freq_t - SUBDEV_PROP_FREQ_MIN, //ro, freq_t + SUBDEV_PROP_FREQ_RANGE, //ro, freq_range_t SUBDEV_PROP_ANTENNA, //rw, std::string SUBDEV_PROP_ANTENNA_NAMES, //ro, prop_names_t SUBDEV_PROP_ENABLED, //rw, bool diff --git a/host/include/uhd/simple_device.hpp b/host/include/uhd/simple_device.hpp index 69f13a8b5..c43155ff2 100644 --- a/host/include/uhd/simple_device.hpp +++ b/host/include/uhd/simple_device.hpp @@ -71,14 +71,11 @@ public: virtual std::vector get_rx_rates(void) = 0; virtual tune_result_t set_rx_freq(double freq) = 0; - virtual double get_rx_freq_min(void) = 0; - virtual double get_rx_freq_max(void) = 0; + virtual std::vector get_rx_freq_range(void) = 0; virtual void set_rx_gain(float gain) = 0; virtual float get_rx_gain(void) = 0; - virtual float get_rx_gain_min(void) = 0; - virtual float get_rx_gain_max(void) = 0; - virtual float get_rx_gain_step(void) = 0; + virtual std::vector get_rx_gain_range(void) = 0; virtual void set_rx_antenna(const std::string &ant) = 0; virtual std::string get_rx_antenna(void) = 0; @@ -92,14 +89,11 @@ public: virtual std::vector get_tx_rates(void) = 0; virtual tune_result_t set_tx_freq(double freq) = 0; - virtual double get_tx_freq_min(void) = 0; - virtual double get_tx_freq_max(void) = 0; + virtual std::vector get_tx_freq_range(void) = 0; virtual void set_tx_gain(float gain) = 0; virtual float get_tx_gain(void) = 0; - virtual float get_tx_gain_min(void) = 0; - virtual float get_tx_gain_max(void) = 0; - virtual float get_tx_gain_step(void) = 0; + virtual std::vector get_tx_gain_range(void) = 0; virtual void set_tx_antenna(const std::string &ant) = 0; virtual std::string get_tx_antenna(void) = 0; diff --git a/host/include/uhd/utils.hpp b/host/include/uhd/utils.hpp index 5d6a18b3a..2f6e4fd87 100644 --- a/host/include/uhd/utils.hpp +++ b/host/include/uhd/utils.hpp @@ -70,11 +70,6 @@ namespace std{ return has(iterable.begin(), iterable.end(), elem); } - template - T sum(const T &a, const T &b){ - return a + b; - } - template T signum(T n){ if (n < 0) return -1; if (n > 0) return 1; diff --git a/host/lib/gain_handler.cpp b/host/lib/gain_handler.cpp index 8f840ae7f..7eb87558c 100644 --- a/host/lib/gain_handler.cpp +++ b/host/lib/gain_handler.cpp @@ -25,16 +25,6 @@ using namespace uhd; -/*********************************************************************** - * helper functions - **********************************************************************/ -static gain_t gain_max(gain_t a, gain_t b){ - return std::max(a, b); -} -static gain_t gain_sum(gain_t a, gain_t b){ - return std::sum(a, b); -} - /*********************************************************************** * gain handler implementation interface **********************************************************************/ @@ -42,7 +32,7 @@ class gain_handler_impl : public gain_handler{ public: gain_handler_impl( const wax::obj &link, - const gain_props_t &gain_props, + const props_t &props, is_equal_t is_equal ); ~gain_handler_impl(void); @@ -51,15 +41,15 @@ public: private: wax::obj _link; - gain_props_t _gain_props; + props_t _props; is_equal_t _is_equal; prop_names_t get_gain_names(void); - std::vector get_gains(const wax::obj &prop_key); gain_t get_overall_gain_val(void); - gain_t get_overall_gain_min(void); - gain_t get_overall_gain_max(void); - gain_t get_overall_gain_step(void); + gain_range_t get_overall_gain_range(void); + template T get_named_prop(const wax::obj &prop, const std::string &name){ + return wax::cast(_link[named_prop_t(prop, name)]); + } }; /*********************************************************************** @@ -67,26 +57,26 @@ private: **********************************************************************/ gain_handler::sptr gain_handler::make( const wax::obj &link, - const gain_props_t &gain_props, + const props_t &props, is_equal_t is_equal ){ - return sptr(new gain_handler_impl(link, gain_props, is_equal)); + return sptr(new gain_handler_impl(link, props, is_equal)); } /*********************************************************************** * gain handler implementation methods **********************************************************************/ -gain_handler::gain_props_t::gain_props_t(void){ +gain_handler::props_t::props_t(void){ /* NOP */ } gain_handler_impl::gain_handler_impl( const wax::obj &link, - const gain_props_t &gain_props, + const props_t &props, is_equal_t is_equal ){ _link = link; - _gain_props = gain_props; + _props = props; _is_equal = is_equal; } @@ -95,31 +85,28 @@ gain_handler_impl::~gain_handler_impl(void){ } prop_names_t gain_handler_impl::get_gain_names(void){ - return wax::cast(_link[_gain_props.gain_names_prop]); + return wax::cast(_link[_props.names]); } -std::vector gain_handler_impl::get_gains(const wax::obj &prop_key){ - std::vector gains; +gain_t gain_handler_impl::get_overall_gain_val(void){ + gain_t gain_val = 0; BOOST_FOREACH(std::string name, get_gain_names()){ - gains.push_back(wax::cast(_link[named_prop_t(prop_key, name)])); + gain_val += get_named_prop(_props.value, name); } - return gains; -} - -gain_t gain_handler_impl::get_overall_gain_val(void){ - return std::reduce(get_gains(_gain_props.gain_val_prop), gain_sum); -} - -gain_t gain_handler_impl::get_overall_gain_min(void){ - return std::reduce(get_gains(_gain_props.gain_min_prop), gain_sum); -} - -gain_t gain_handler_impl::get_overall_gain_max(void){ - return std::reduce(get_gains(_gain_props.gain_max_prop), gain_sum); + return gain_val; } -gain_t gain_handler_impl::get_overall_gain_step(void){ - return std::reduce(get_gains(_gain_props.gain_step_prop), gain_max); +gain_range_t gain_handler_impl::get_overall_gain_range(void){ + gain_t gain_min = 0, gain_max = 0, gain_step = 0; + BOOST_FOREACH(std::string name, get_gain_names()){ + gain_t gain_min_tmp, gain_max_tmp, gain_step_tmp; + boost::tie(gain_min_tmp, gain_max_tmp, gain_step_tmp) = \ + get_named_prop(_props.range, name); + gain_min += gain_min_tmp; + gain_max += gain_max_tmp; + gain_step = std::max(gain_step, gain_step_tmp); + } + return gain_range_t(gain_min, gain_max, gain_step); } /*********************************************************************** @@ -135,23 +122,13 @@ bool gain_handler_impl::intercept_get(const wax::obj &key_, wax::obj &val){ return false; } - if (_is_equal(key, _gain_props.gain_val_prop)){ + if (_is_equal(key, _props.value)){ val = get_overall_gain_val(); return true; } - if (_is_equal(key, _gain_props.gain_min_prop)){ - val = get_overall_gain_min(); - return true; - } - - if (_is_equal(key, _gain_props.gain_max_prop)){ - val = get_overall_gain_max(); - return true; - } - - if (_is_equal(key, _gain_props.gain_step_prop)){ - val = get_overall_gain_step(); + if (_is_equal(key, _props.range)){ + val = get_overall_gain_range(); return true; } @@ -166,15 +143,16 @@ bool gain_handler_impl::intercept_set(const wax::obj &key_, const wax::obj &val) boost::tie(key, name) = extract_named_prop(key_); //not a gain value key... dont handle - if (not _is_equal(key, _gain_props.gain_val_prop)) return false; + if (not _is_equal(key, _props.value)) return false; gain_t gain_val = wax::cast(val); //not a wildcard... dont handle (but check name and range) if (name != ""){ assert_has(get_gain_names(), name, "gain name"); - gain_t gain_min = wax::cast(_link[named_prop_t(_gain_props.gain_min_prop, name)]); - gain_t gain_max = wax::cast(_link[named_prop_t(_gain_props.gain_max_prop, name)]); + gain_t gain_min, gain_max, gain_step; + boost::tie(gain_min, gain_max, gain_step) = \ + get_named_prop(_props.range, name); if (gain_val > gain_max or gain_val < gain_min) throw std::range_error(str( boost::format("A value of %f for gain %s is out of range of (%f, %f)") % gain_val % name % gain_min % gain_max @@ -185,16 +163,16 @@ bool gain_handler_impl::intercept_set(const wax::obj &key_, const wax::obj &val) //set the overall gain BOOST_FOREACH(std::string name, get_gain_names()){ //get the min, max, step for this gain name - gain_t gain_min = wax::cast(_link[named_prop_t(_gain_props.gain_min_prop, name)]); - gain_t gain_max = wax::cast(_link[named_prop_t(_gain_props.gain_max_prop, name)]); - gain_t gain_step = wax::cast(_link[named_prop_t(_gain_props.gain_step_prop, name)]); + gain_t gain_min, gain_max, gain_step; + boost::tie(gain_min, gain_max, gain_step) = \ + get_named_prop(_props.range, name); //clip g to be within the allowed range gain_t g = std::min(std::max(gain_val, gain_min), gain_max); //set g to be a multiple of the step size g -= fmod(g, gain_step); //set g to be the new gain - _link[named_prop_t(_gain_props.gain_val_prop, name)] = g; + _link[named_prop_t(_props.value, name)] = g; //subtract g out of the total gain left to apply gain_val -= g; } diff --git a/host/lib/simple_device.cpp b/host/lib/simple_device.cpp index 76f3c1262..ac83ffaed 100644 --- a/host/lib/simple_device.cpp +++ b/host/lib/simple_device.cpp @@ -188,12 +188,11 @@ public: return tune(target_freq, lo_offset, _rx_subdev, _rx_ddc, false/* not tx */); } - double get_rx_freq_min(void){ - return wax::cast(_rx_subdev[SUBDEV_PROP_FREQ_MIN]); - } - - double get_rx_freq_max(void){ - return wax::cast(_rx_subdev[SUBDEV_PROP_FREQ_MAX]); + std::vector get_rx_freq_range(void){ + std::vector range(2); + boost::tie(range[0], range[1]) = \ + wax::cast(_rx_subdev[SUBDEV_PROP_FREQ_RANGE]); + return range; } void set_rx_gain(float gain){ @@ -201,19 +200,14 @@ public: } float get_rx_gain(void){ - return wax::cast(_rx_subdev[SUBDEV_PROP_GAIN]); - } - - float get_rx_gain_min(void){ - return wax::cast(_rx_subdev[SUBDEV_PROP_GAIN_MIN]); - } - - float get_rx_gain_max(void){ - return wax::cast(_rx_subdev[SUBDEV_PROP_GAIN_MAX]); + return wax::cast(_rx_subdev[SUBDEV_PROP_GAIN]); } - float get_rx_gain_step(void){ - return wax::cast(_rx_subdev[SUBDEV_PROP_GAIN_STEP]); + std::vector get_rx_gain_range(void){ + std::vector range(3); + boost::tie(range[0], range[1], range[2]) = \ + wax::cast(_rx_subdev[SUBDEV_PROP_GAIN_RANGE]); + return range; } void set_rx_antenna(const std::string &ant){ @@ -256,12 +250,11 @@ public: return tune(target_freq, lo_offset, _tx_subdev, _tx_duc, true/* is tx */); } - double get_tx_freq_min(void){ - return wax::cast(_tx_subdev[SUBDEV_PROP_FREQ_MIN]); - } - - double get_tx_freq_max(void){ - return wax::cast(_tx_subdev[SUBDEV_PROP_FREQ_MAX]); + std::vector get_tx_freq_range(void){ + std::vector range(2); + boost::tie(range[0], range[1]) = \ + wax::cast(_tx_subdev[SUBDEV_PROP_FREQ_RANGE]); + return range; } void set_tx_gain(float gain){ @@ -269,19 +262,14 @@ public: } float get_tx_gain(void){ - return wax::cast(_tx_subdev[SUBDEV_PROP_GAIN]); - } - - float get_tx_gain_min(void){ - return wax::cast(_tx_subdev[SUBDEV_PROP_GAIN_MIN]); - } - - float get_tx_gain_max(void){ - return wax::cast(_tx_subdev[SUBDEV_PROP_GAIN_MAX]); + return wax::cast(_tx_subdev[SUBDEV_PROP_GAIN]); } - float get_tx_gain_step(void){ - return wax::cast(_tx_subdev[SUBDEV_PROP_GAIN_STEP]); + std::vector get_tx_gain_range(void){ + std::vector range(3); + boost::tie(range[0], range[1], range[2]) = \ + wax::cast(_tx_subdev[SUBDEV_PROP_GAIN_RANGE]); + return range; } void set_tx_antenna(const std::string &ant){ diff --git a/host/lib/usrp/dboard/basic.cpp b/host/lib/usrp/dboard/basic.cpp index 4b74e4a47..1059feb19 100644 --- a/host/lib/usrp/dboard/basic.cpp +++ b/host/lib/usrp/dboard/basic.cpp @@ -111,12 +111,13 @@ void basic_rx::rx_get(const wax::obj &key_, wax::obj &val){ return; case SUBDEV_PROP_GAIN: - case SUBDEV_PROP_GAIN_MAX: - case SUBDEV_PROP_GAIN_MIN: - case SUBDEV_PROP_GAIN_STEP: val = gain_t(0); return; + case SUBDEV_PROP_GAIN_RANGE: + val = gain_range_t(0, 0, 0); + return; + case SUBDEV_PROP_GAIN_NAMES: val = prop_names_t(); //empty return; @@ -125,12 +126,8 @@ void basic_rx::rx_get(const wax::obj &key_, wax::obj &val){ val = freq_t(0); return; - case SUBDEV_PROP_FREQ_MAX: - val = +_max_freq; - return; - - case SUBDEV_PROP_FREQ_MIN: - val = -_max_freq; + case SUBDEV_PROP_FREQ_RANGE: + val = freq_range_t(+_max_freq, -_max_freq); return; case SUBDEV_PROP_ANTENNA: @@ -177,13 +174,10 @@ void basic_rx::rx_set(const wax::obj &key_, const wax::obj &val){ case SUBDEV_PROP_NAME: case SUBDEV_PROP_OTHERS: - case SUBDEV_PROP_GAIN_MAX: - case SUBDEV_PROP_GAIN_MIN: - case SUBDEV_PROP_GAIN_STEP: + case SUBDEV_PROP_GAIN_RANGE: case SUBDEV_PROP_GAIN_NAMES: case SUBDEV_PROP_FREQ: - case SUBDEV_PROP_FREQ_MAX: - case SUBDEV_PROP_FREQ_MIN: + case SUBDEV_PROP_FREQ_RANGE: case SUBDEV_PROP_ANTENNA_NAMES: case SUBDEV_PROP_QUADRATURE: case SUBDEV_PROP_IQ_SWAPPED: @@ -223,12 +217,13 @@ void basic_tx::tx_get(const wax::obj &key_, wax::obj &val){ return; case SUBDEV_PROP_GAIN: - case SUBDEV_PROP_GAIN_MAX: - case SUBDEV_PROP_GAIN_MIN: - case SUBDEV_PROP_GAIN_STEP: val = gain_t(0); return; + case SUBDEV_PROP_GAIN_RANGE: + val = gain_range_t(0, 0, 0); + return; + case SUBDEV_PROP_GAIN_NAMES: val = prop_names_t(); //empty return; @@ -237,12 +232,8 @@ void basic_tx::tx_get(const wax::obj &key_, wax::obj &val){ val = freq_t(0); return; - case SUBDEV_PROP_FREQ_MAX: - val = +_max_freq; - return; - - case SUBDEV_PROP_FREQ_MIN: - val = -_max_freq; + case SUBDEV_PROP_FREQ_RANGE: + val = freq_range_t(+_max_freq, -_max_freq); return; case SUBDEV_PROP_ANTENNA: @@ -289,13 +280,10 @@ void basic_tx::tx_set(const wax::obj &key_, const wax::obj &val){ case SUBDEV_PROP_NAME: case SUBDEV_PROP_OTHERS: - case SUBDEV_PROP_GAIN_MAX: - case SUBDEV_PROP_GAIN_MIN: - case SUBDEV_PROP_GAIN_STEP: + case SUBDEV_PROP_GAIN_RANGE: case SUBDEV_PROP_GAIN_NAMES: case SUBDEV_PROP_FREQ: - case SUBDEV_PROP_FREQ_MAX: - case SUBDEV_PROP_FREQ_MIN: + case SUBDEV_PROP_FREQ_RANGE: case SUBDEV_PROP_ANTENNA_NAMES: case SUBDEV_PROP_QUADRATURE: case SUBDEV_PROP_IQ_SWAPPED: diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp index 08b92e62a..23c2921d2 100644 --- a/host/lib/usrp/dboard_manager.cpp +++ b/host/lib/usrp/dboard_manager.cpp @@ -70,16 +70,15 @@ public: subdev_proxy(dboard_base::sptr subdev, type_t type) : _subdev(subdev), _type(type){ //initialize gain props struct - gain_handler::gain_props_t gain_props; - gain_props.gain_val_prop = SUBDEV_PROP_GAIN; - gain_props.gain_min_prop = SUBDEV_PROP_GAIN_MIN; - gain_props.gain_max_prop = SUBDEV_PROP_GAIN_MAX; - gain_props.gain_step_prop = SUBDEV_PROP_GAIN_STEP; - gain_props.gain_names_prop = SUBDEV_PROP_GAIN_NAMES; + gain_handler::props_t gain_props; + gain_props.value = SUBDEV_PROP_GAIN; + gain_props.range = SUBDEV_PROP_GAIN_RANGE; + gain_props.names = SUBDEV_PROP_GAIN_NAMES; //make a new gain handler _gain_handler = gain_handler::make( - this->get_link(), gain_props, boost::bind(&gain_handler::is_equal, _1, _2) + this->get_link(), gain_props, + boost::bind(&gain_handler::is_equal, _1, _2) ); } diff --git a/host/test/gain_handler_test.cpp b/host/test/gain_handler_test.cpp index 9a6a50dab..51497b741 100644 --- a/host/test/gain_handler_test.cpp +++ b/host/test/gain_handler_test.cpp @@ -25,10 +25,8 @@ using namespace uhd; enum prop_t{ - PROP_GAIN, - PROP_GAIN_MIN, - PROP_GAIN_MAX, - PROP_GAIN_STEP, + PROP_GAIN_VALUE, + PROP_GAIN_RANGE, PROP_GAIN_NAMES }; @@ -36,24 +34,19 @@ class gainful_obj : public wax::obj{ public: gainful_obj(void){ //initialize gain props struct - gain_handler::gain_props_t gain_props; - gain_props.gain_val_prop = PROP_GAIN; - gain_props.gain_min_prop = PROP_GAIN_MIN; - gain_props.gain_max_prop = PROP_GAIN_MAX; - gain_props.gain_step_prop = PROP_GAIN_STEP; - gain_props.gain_names_prop = PROP_GAIN_NAMES; + gain_handler::props_t gain_props; + gain_props.value = PROP_GAIN_VALUE; + gain_props.range = PROP_GAIN_RANGE; + gain_props.names = PROP_GAIN_NAMES; //make a new gain handler _gain_handler = gain_handler::make( - this->get_link(), gain_props, boost::bind(&gain_handler::is_equal, _1, _2) + this->get_link(), gain_props, + boost::bind(&gain_handler::is_equal, _1, _2) ); - _gains["g0"] = 0; - _gains["g1"] = 0; - _gains_min["g0"] = -10; - _gains_min["g1"] = 0; - _gains_max["g0"] = 0; - _gains_max["g1"] = 100; - _gains_step["g0"] = .1; - _gains_step["g1"] = 1.5; + _gain_values["g0"] = 0; + _gain_values["g1"] = 0; + _gain_ranges["g0"] = gain_range_t(-10, 0, .1); + _gain_ranges["g1"] = gain_range_t(0, 100, 1.5); } ~gainful_obj(void){} @@ -67,24 +60,16 @@ private: //handle the get request conditioned on the key switch(wax::cast(key)){ - case PROP_GAIN: - val = _gains[name]; + case PROP_GAIN_VALUE: + val = _gain_values[name]; return; - case PROP_GAIN_MIN: - val = _gains_min[name]; - return; - - case PROP_GAIN_MAX: - val = _gains_max[name]; - return; - - case PROP_GAIN_STEP: - val = _gains_step[name]; + case PROP_GAIN_RANGE: + val = _gain_ranges[name]; return; case PROP_GAIN_NAMES: - val = prop_names_t(_gains.get_keys()); + val = _gain_values.get_keys(); return; } } @@ -97,23 +82,19 @@ private: //handle the get request conditioned on the key switch(wax::cast(key)){ - case PROP_GAIN: - _gains[name] = wax::cast(val); + case PROP_GAIN_VALUE: + _gain_values[name] = wax::cast(val); return; - case PROP_GAIN_MIN: - case PROP_GAIN_MAX: - case PROP_GAIN_STEP: + case PROP_GAIN_RANGE: case PROP_GAIN_NAMES: throw std::runtime_error("cannot set this property"); } } gain_handler::sptr _gain_handler; - uhd::dict _gains; - uhd::dict _gains_min; - uhd::dict _gains_max; - uhd::dict _gains_step; + uhd::dict _gain_values; + uhd::dict _gain_ranges; }; @@ -122,17 +103,20 @@ BOOST_AUTO_TEST_CASE(test_gain_handler){ gainful_obj go0; BOOST_CHECK_THROW( - wax::cast(go0[named_prop_t(PROP_GAIN, "fail")]), + wax::cast(go0[named_prop_t(PROP_GAIN_VALUE, "fail")]), std::exception ); std::cout << "verifying the overall min, max, step" << std::endl; - BOOST_CHECK_EQUAL(wax::cast(go0[PROP_GAIN_MIN]), gain_t(-10)); - BOOST_CHECK_EQUAL(wax::cast(go0[PROP_GAIN_MAX]), gain_t(100)); - BOOST_CHECK_EQUAL(wax::cast(go0[PROP_GAIN_STEP]), gain_t(1.5)); + gain_t gain_min, gain_max, gain_step; + boost::tie(gain_min, gain_max, gain_step) = \ + wax::cast(go0[PROP_GAIN_RANGE]); + BOOST_CHECK_EQUAL(gain_min, gain_t(-10)); + BOOST_CHECK_EQUAL(gain_max, gain_t(100)); + BOOST_CHECK_EQUAL(gain_step, gain_t(1.5)); std::cout << "verifying the overall gain" << std::endl; - go0[named_prop_t(PROP_GAIN, "g0")] = gain_t(-5); - go0[named_prop_t(PROP_GAIN, "g1")] = gain_t(30); - BOOST_CHECK_EQUAL(wax::cast(go0[PROP_GAIN]), gain_t(25)); + go0[named_prop_t(PROP_GAIN_VALUE, "g0")] = gain_t(-5); + go0[named_prop_t(PROP_GAIN_VALUE, "g1")] = gain_t(30); + BOOST_CHECK_EQUAL(wax::cast(go0[PROP_GAIN_VALUE]), gain_t(25)); } -- cgit v1.2.3 From 1ba6aafa678cdf61aef44de1d22ec72653e87ec7 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 12 Mar 2010 18:04:31 -0800 Subject: handle getting and setting mac and ip addr from the host --- host/lib/usrp/usrp2/mboard_impl.cpp | 69 +++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 47e22c473..b66de8262 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -16,6 +16,7 @@ // #include +#include #include "usrp2_impl.hpp" using namespace uhd; @@ -88,14 +89,50 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ wax::obj key; std::string name; boost::tie(key, name) = extract_named_prop(key_); + //handle the other props + if (key.type() == typeid(std::string)){ + if (wax::cast(key) == "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 = ctrl_send_and_recv(out_data); + ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE); + + //extract the address + val = reinterpret_cast(in_data.data.mac_addr)->to_string(); + return; + } + + if (wax::cast(key) == "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 = ctrl_send_and_recv(out_data); + 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(); + return; + } + } + //handle the get request conditioned on the key switch(wax::cast(key)){ case MBOARD_PROP_NAME: val = std::string("usrp2 mboard"); return; - case MBOARD_PROP_OTHERS: - val = prop_names_t(); //empty other props + case MBOARD_PROP_OTHERS:{ + prop_names_t others = boost::assign::list_of + ("mac-addr") + ("ip-addr") + ; + val = others; + } return; case MBOARD_PROP_RX_DBOARD: @@ -169,6 +206,34 @@ 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){ + //handle the other props + if (key.type() == typeid(std::string)){ + if (wax::cast(key) == "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(wax::cast(val)); + std::memcpy(out_data.data.mac_addr, &mac_addr, sizeof(mac_addr_t)); + + //send and recv + usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); + ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_MAC_ADDR_DUDE); + return; + } + + if (wax::cast(key) == "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(wax::cast(val)).to_ulong()); + + //send and recv + usrp2_ctrl_data_t in_data = ctrl_send_and_recv(out_data); + ASSERT_THROW(htonl(in_data.id) == USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE); + return; + } + } + //handle the get request conditioned on the key switch(wax::cast(key)){ -- cgit v1.2.3 From 7590f187d0414fd05e23828488166bc4bc88df26 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 15 Mar 2010 12:15:33 -0700 Subject: Device sub classes can register themselves. Simplifies device.cpp internals. Added static instance macro for lazy instantiation of static variables. --- host/include/uhd/device.hpp | 13 +++++ host/include/uhd/dict.hpp | 8 +++ host/include/uhd/usrp/dboard_manager.hpp | 4 +- host/include/uhd/utils.hpp | 13 ++++- host/lib/device.cpp | 92 ++++++++++++++++---------------- host/lib/usrp/dboard/basic.cpp | 8 +-- host/lib/usrp/dboard_manager.cpp | 53 +++++++++--------- host/lib/usrp/usrp2/usrp2_impl.cpp | 5 +- 8 files changed, 117 insertions(+), 79 deletions(-) diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index 47dfa4328..c9d608bcf 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -37,6 +37,19 @@ class device : boost::noncopyable, public wax::obj{ public: typedef boost::shared_ptr sptr; + typedef boost::function discover_t; + typedef boost::function make_t; + + /*! + * Register a device into the discovery and factory system. + * + * \param discover a function that discovers devices + * \param make a factory function that makes a device + */ + static void register_device( + const discover_t &discover, + const make_t &make + ); /*! * \brief Discover usrp devices attached to the host. diff --git a/host/include/uhd/dict.hpp b/host/include/uhd/dict.hpp index 1ed28551a..2224a0063 100644 --- a/host/include/uhd/dict.hpp +++ b/host/include/uhd/dict.hpp @@ -56,6 +56,14 @@ namespace uhd{ /* NOP */ } + /*! + * Get the number of elements in this dict. + * \param the number of elements + */ + std::size_t size(void) const{ + return _map.size(); + } + /*! * Get a list of the keys in this dict. * \return vector of keys diff --git a/host/include/uhd/usrp/dboard_manager.hpp b/host/include/uhd/usrp/dboard_manager.hpp index cf69675fc..0c32c6dba 100644 --- a/host/include/uhd/usrp/dboard_manager.hpp +++ b/host/include/uhd/usrp/dboard_manager.hpp @@ -40,14 +40,14 @@ public: typedef dboard_base::sptr(*dboard_ctor_t)(dboard_base::ctor_args_t const&); /*! - * Register subdevices for a given dboard id. + * Register a dboard into the system. * * \param dboard_id the dboard id (rx or tx) * \param dboard_ctor the dboard constructor function pointer * \param name the canonical name for the dboard represented * \param subdev_names the names of the subdevs on this dboard */ - static void register_subdevs( + static void register_dboard( dboard_id_t dboard_id, dboard_ctor_t dboard_ctor, const std::string &name, diff --git a/host/include/uhd/utils.hpp b/host/include/uhd/utils.hpp index 2f6e4fd87..995cb9926 100644 --- a/host/include/uhd/utils.hpp +++ b/host/include/uhd/utils.hpp @@ -23,10 +23,19 @@ #include #include +/*! + * Defines a function that implements the "construct on first use" idiom + * \param _t the type definition for the instance + * \param _x the name of the defined function + * \return a reference to the lazy instance + */ +#define STATIC_INSTANCE(_t, _x) static _t &_x(){static _t _x; return _x;} + /*! * Defines a static code block that will be called before main() + * \param _x the name of the defined struct (must be unique in file) */ -#define STATIC_BLOCK(_x) struct _x{_x();}_x;_x::_x() +#define STATIC_BLOCK(_x) static struct _x{_x();}_x;_x::_x() /*! * Useful templated functions and classes that I like to pretend are part of stl @@ -42,7 +51,7 @@ namespace std{ #define ASSERT_THROW(_x) if (not (_x)) { \ throw std::assert_error(str(boost::format( \ - "Assertion Failed:\n %s:%d\n %s\n __/ %s __/" \ + "Assertion Failed:\n %s:%d\n %s\n ---> %s <---" \ ) % __FILE__ % __LINE__ % BOOST_CURRENT_FUNCTION % std::string(#_x))); \ } diff --git a/host/lib/device.cpp b/host/lib/device.cpp index 4b64e4a15..a87ba83eb 100644 --- a/host/lib/device.cpp +++ b/host/lib/device.cpp @@ -15,49 +15,22 @@ // asize_t with this program. If not, see . // -#include -#include +#include #include #include #include #include #include #include +#include #include #include using namespace uhd; -/*! - * Create a new device from a device address. - * Based on the address, call the appropriate make functions. - * \param dev_addr the device address - * \param hint the device address that was used to find the device - * \return a smart pointer to a device - */ -static device::sptr make_device(const device_addr_t &dev_addr_, const device_addr_t &hint){ - //copy keys that were in hint but not in dev_addr - //this way, we can pass additional transport arguments - device_addr_t dev_addr = dev_addr_; - BOOST_FOREACH(std::string key, hint.get_keys()){ - if (not dev_addr.has_key(key)) dev_addr[key] = hint[key]; - } - - //create a usrp1e - if (dev_addr["type"] == "usrp1e"){ - return usrp::usrp1e::make(dev_addr); - } - - //create a usrp2 - if (dev_addr["type"] == "usrp2"){ - return usrp::usrp2::make(dev_addr); - } - - throw std::runtime_error(str( - boost::format("Cant make a device for %s") % device_addr::to_string(dev_addr) - )); -} - +/*********************************************************************** + * Helper Functions + **********************************************************************/ /*! * Make a device hash that maps 1 to 1 with a device address. * The hash will be used to identify created devices. @@ -80,20 +53,35 @@ static size_t hash_device_addr( return hash; } +/*********************************************************************** + * Registration + **********************************************************************/ +typedef boost::tuple dev_fcn_reg_t; + +// instantiate the device function registry container +STATIC_INSTANCE(std::vector, get_dev_fcn_regs) + +void device::register_device( + const discover_t &discover, + const make_t &make +){ + //std::cout << "registering device" << std::endl; + get_dev_fcn_regs().push_back(dev_fcn_reg_t(discover, make)); +} + /*********************************************************************** * Discover **********************************************************************/ device_addrs_t device::discover(const device_addr_t &hint){ device_addrs_t device_addrs; - //discover the usrp1es - std::vector usrp2_addrs = usrp::usrp1e::discover(hint); - device_addrs.insert(device_addrs.begin(), usrp2_addrs.begin(), usrp2_addrs.end()); - - //discover the usrp2s - if (hint.has_key("addr")){ - std::vector usrp2_addrs = usrp::usrp2::discover(hint); - device_addrs.insert(device_addrs.begin(), usrp2_addrs.begin(), usrp2_addrs.end()); + BOOST_FOREACH(dev_fcn_reg_t fcn, get_dev_fcn_regs()){ + device_addrs_t discovered_addrs = fcn.get<0>()(hint); + device_addrs.insert( + device_addrs.begin(), + discovered_addrs.begin(), + discovered_addrs.end() + ); } return device_addrs; @@ -103,24 +91,38 @@ device_addrs_t device::discover(const device_addr_t &hint){ * Make **********************************************************************/ device::sptr device::make(const device_addr_t &hint, size_t which){ - std::vector device_addrs = discover(hint); + typedef boost::tuple dev_addr_make_t; + std::vector dev_addr_makers; + + BOOST_FOREACH(dev_fcn_reg_t fcn, get_dev_fcn_regs()){ + BOOST_FOREACH(device_addr_t dev_addr, fcn.get<0>()(hint)){ + //copy keys that were in hint but not in dev_addr + //this way, we can pass additional transport arguments + BOOST_FOREACH(std::string key, hint.get_keys()){ + if (not dev_addr.has_key(key)) dev_addr[key] = hint[key]; + } + //append the discovered address and its factory function + dev_addr_makers.push_back(dev_addr_make_t(dev_addr, fcn.get<1>())); + } + } //check that we found any devices - if (device_addrs.size() == 0){ + if (dev_addr_makers.size() == 0){ throw std::runtime_error(str( boost::format("No devices found for %s") % device_addr::to_string(hint) )); } //check that the which index is valid - if (device_addrs.size() <= which){ + if (dev_addr_makers.size() <= which){ throw std::runtime_error(str( boost::format("No device at index %d for %s") % which % device_addr::to_string(hint) )); } //create a unique hash for the device address - device_addr_t dev_addr = device_addrs.at(which); + device_addr_t dev_addr; make_t maker; + boost::tie(dev_addr, maker) = dev_addr_makers.at(which); size_t dev_hash = hash_device_addr(dev_addr); //std::cout << boost::format("Hash: %u") % dev_hash << std::endl; @@ -135,7 +137,7 @@ device::sptr device::make(const device_addr_t &hint, size_t which){ } //create and register a new device catch(const std::assert_error &e){ - device::sptr dev = make_device(dev_addr, hint); + device::sptr dev = maker(dev_addr); hash_to_device[dev_hash] = dev; return dev; } diff --git a/host/lib/usrp/dboard/basic.cpp b/host/lib/usrp/dboard/basic.cpp index 1059feb19..e719950e8 100644 --- a/host/lib/usrp/dboard/basic.cpp +++ b/host/lib/usrp/dboard/basic.cpp @@ -74,10 +74,10 @@ static dboard_base::sptr make_lf_tx(dboard_base::ctor_args_t const& args){ } STATIC_BLOCK(reg_dboards){ - dboard_manager::register_subdevs(0x0000, &make_basic_tx, "Basic TX", list_of("")); - dboard_manager::register_subdevs(0x0001, &make_basic_rx, "Basic RX", list_of("a")("b")("ab")); - dboard_manager::register_subdevs(0x000e, &make_lf_tx, "LF TX", list_of("")); - dboard_manager::register_subdevs(0x000f, &make_lf_rx, "LF RX", list_of("a")("b")("ab")); + dboard_manager::register_dboard(0x0000, &make_basic_tx, "Basic TX", list_of("")); + dboard_manager::register_dboard(0x0001, &make_basic_rx, "Basic RX", list_of("a")("b")("ab")); + dboard_manager::register_dboard(0x000e, &make_lf_tx, "LF TX", list_of("")); + dboard_manager::register_dboard(0x000f, &make_lf_rx, "LF RX", list_of("a")("b")("ab")); } /*********************************************************************** diff --git a/host/lib/usrp/dboard_manager.cpp b/host/lib/usrp/dboard_manager.cpp index 23c2921d2..eeabbda99 100644 --- a/host/lib/usrp/dboard_manager.cpp +++ b/host/lib/usrp/dboard_manager.cpp @@ -30,27 +30,30 @@ using namespace uhd::usrp; /*********************************************************************** * storage and registering for dboards **********************************************************************/ -typedef boost::tuple args_t; +//dboard registry tuple: dboard constructor, canonical name, subdev names +typedef boost::tuple args_t; //map a dboard id to a dboard constructor -static uhd::dict id_to_args_map; +typedef uhd::dict id_to_args_map_t; +STATIC_INSTANCE(id_to_args_map_t, get_id_to_args_map) -//map a dboard id to a canonical name -static uhd::dict id_to_str; - -void dboard_manager::register_subdevs( +void dboard_manager::register_dboard( dboard_id_t dboard_id, dboard_ctor_t dboard_ctor, const std::string &name, const prop_names_t &subdev_names ){ //std::cout << "registering: " << name << std::endl; - id_to_str[dboard_id] = name; - id_to_args_map[dboard_id] = args_t(dboard_ctor, subdev_names); + if (get_id_to_args_map().has_key(dboard_id)){ + throw std::runtime_error(str(boost::format( + "The dboard id 0x%.4x is already registered to %s." + ) % dboard_id % dboard_id::to_string(dboard_id))); + } + get_id_to_args_map()[dboard_id] = args_t(dboard_ctor, name, subdev_names); } std::string dboard_id::to_string(const dboard_id_t &id){ - std::string name = (id_to_str.has_key(id))? id_to_str[id] : "unknown"; + std::string name = (get_id_to_args_map().has_key(id))? get_id_to_args_map()[id].get<1>() : "unknown"; return str(boost::format("%s (0x%.4x)") % name % id); } @@ -170,7 +173,7 @@ static args_t get_dboard_args( } //verify that there is a registered constructor for this id - if (not id_to_args_map.has_key(dboard_id)){ + if (not get_id_to_args_map().has_key(dboard_id)){ throw std::runtime_error(str( boost::format("Unregistered %s dboard id: %s") % xx_type % dboard_id::to_string(dboard_id) @@ -178,7 +181,7 @@ static args_t get_dboard_args( } //return the dboard args for this id - return id_to_args_map[dboard_id]; + return get_id_to_args_map()[dboard_id]; } dboard_manager_impl::dboard_manager_impl( @@ -188,11 +191,11 @@ dboard_manager_impl::dboard_manager_impl( ){ _interface = interface; - dboard_ctor_t rx_dboard_ctor; prop_names_t rx_subdevs; - boost::tie(rx_dboard_ctor, rx_subdevs) = get_dboard_args(rx_dboard_id, "rx"); + dboard_ctor_t rx_dboard_ctor; std::string rx_name; prop_names_t rx_subdevs; + boost::tie(rx_dboard_ctor, rx_name, rx_subdevs) = get_dboard_args(rx_dboard_id, "rx"); - dboard_ctor_t tx_dboard_ctor; prop_names_t tx_subdevs; - boost::tie(tx_dboard_ctor, tx_subdevs) = get_dboard_args(tx_dboard_id, "tx"); + dboard_ctor_t tx_dboard_ctor; std::string tx_name; prop_names_t tx_subdevs; + boost::tie(tx_dboard_ctor, tx_name, tx_subdevs) = get_dboard_args(tx_dboard_id, "tx"); //initialize the gpio pins before creating subdevs set_nice_gpio_pins(); @@ -200,16 +203,16 @@ dboard_manager_impl::dboard_manager_impl( //make xcvr subdevs (make one subdev for both rx and tx dboards) if (rx_dboard_ctor == tx_dboard_ctor){ ASSERT_THROW(rx_subdevs == tx_subdevs); - BOOST_FOREACH(std::string name, rx_subdevs){ + BOOST_FOREACH(std::string subdev, rx_subdevs){ dboard_base::sptr xcvr_dboard = rx_dboard_ctor( - dboard_base::ctor_args_t(name, interface, rx_dboard_id, tx_dboard_id) + dboard_base::ctor_args_t(subdev, interface, rx_dboard_id, tx_dboard_id) ); //create a rx proxy for this xcvr board - _rx_dboards[name] = subdev_proxy::sptr( + _rx_dboards[subdev] = subdev_proxy::sptr( new subdev_proxy(xcvr_dboard, subdev_proxy::RX_TYPE) ); //create a tx proxy for this xcvr board - _tx_dboards[name] = subdev_proxy::sptr( + _tx_dboards[subdev] = subdev_proxy::sptr( new subdev_proxy(xcvr_dboard, subdev_proxy::TX_TYPE) ); } @@ -218,22 +221,22 @@ dboard_manager_impl::dboard_manager_impl( //make tx and rx subdevs (separate subdevs for rx and tx dboards) else{ //make the rx subdevs - BOOST_FOREACH(std::string name, rx_subdevs){ + BOOST_FOREACH(std::string subdev, rx_subdevs){ dboard_base::sptr rx_dboard = rx_dboard_ctor( - dboard_base::ctor_args_t(name, interface, rx_dboard_id, ID_NONE) + dboard_base::ctor_args_t(subdev, interface, rx_dboard_id, ID_NONE) ); //create a rx proxy for this rx board - _rx_dboards[name] = subdev_proxy::sptr( + _rx_dboards[subdev] = subdev_proxy::sptr( new subdev_proxy(rx_dboard, subdev_proxy::RX_TYPE) ); } //make the tx subdevs - BOOST_FOREACH(std::string name, tx_subdevs){ + BOOST_FOREACH(std::string subdev, tx_subdevs){ dboard_base::sptr tx_dboard = tx_dboard_ctor( - dboard_base::ctor_args_t(name, interface, ID_NONE, tx_dboard_id) + dboard_base::ctor_args_t(subdev, interface, ID_NONE, tx_dboard_id) ); //create a tx proxy for this tx board - _tx_dboards[name] = subdev_proxy::sptr( + _tx_dboards[subdev] = subdev_proxy::sptr( new subdev_proxy(tx_dboard, subdev_proxy::TX_TYPE) ); } diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 58c82303f..850a738d4 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -26,6 +26,10 @@ using namespace uhd::usrp; using namespace uhd::transport; namespace asio = boost::asio; +STATIC_BLOCK(register_device){ + device::register_device(&usrp2::discover, &usrp2::make); +} + /*********************************************************************** * Discovery over the udp transport **********************************************************************/ @@ -57,7 +61,6 @@ uhd::device_addrs_t usrp2::discover(const device_addr_t &hint){ boost::asio::ip::address_v4 ip_addr(ntohl(ctrl_data_in.data.ip_addr)); device_addr_t new_addr; new_addr["name"] = "USRP2"; - new_addr["type"] = "usrp2"; new_addr["transport"] = "udp"; new_addr["addr"] = ip_addr.to_string(); usrp2_addrs.push_back(new_addr); -- cgit v1.2.3 From e4997af8453980922b469e5d3b66a7b26910dad3 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 15 Mar 2010 16:00:07 -0700 Subject: Ability to burn mac addr and ip addr to usrp2 (over ip/udp for now). Added firmware support and usrp2 burner host app. --- firmware/microblaze/apps/txrx.c | 44 ++++++++------- firmware/microblaze/include/usrp2_i2c_addr.h | 1 + firmware/microblaze/lib/ethernet.c | 76 +++++++++++++++++++------ firmware/microblaze/lib/ethernet.h | 11 ++++ host/apps/CMakeLists.txt | 5 +- host/apps/usrp2_burner.cpp | 83 ++++++++++++++++++++++++++++ host/include/uhd/wax.hpp | 14 ++++- 7 files changed, 194 insertions(+), 40 deletions(-) create mode 100644 host/apps/usrp2_burner.cpp diff --git a/firmware/microblaze/apps/txrx.c b/firmware/microblaze/apps/txrx.c index 18bbdd23d..97376ffbd 100644 --- a/firmware/microblaze/apps/txrx.c +++ b/firmware/microblaze/apps/txrx.c @@ -153,9 +153,12 @@ static eth_mac_addr_t get_my_eth_mac_addr(void){ } static struct ip_addr get_my_ip_addr(void){ - struct ip_addr addr; - addr.addr = 192 << 24 | 168 << 16 | 10 << 8 | 2 << 0; - return addr; + return *get_ip_addr(); +} + +static void print_ip_addr(const void *t){ + uint8_t *p = (uint8_t *)t; + printf("%d.%d.%d.%d", p[0], p[1], p[2], p[3]); } void handle_udp_data_packet( @@ -170,21 +173,13 @@ void handle_udp_data_packet( printf("Storing for fast path:\n"); printf(" source mac addr: "); print_mac_addr(fp_mac_addr_src.addr); newline(); - printf(" source ip addr: %d.%d.%d.%d\n", - ((const unsigned char*)&fp_socket_src.addr.addr)[0], - ((const unsigned char*)&fp_socket_src.addr.addr)[1], - ((const unsigned char*)&fp_socket_src.addr.addr)[2], - ((const unsigned char*)&fp_socket_src.addr.addr)[3] - ); + printf(" source ip addr: "); + print_ip_addr(&fp_socket_src.addr); newline(); printf(" source udp port: %d\n", fp_socket_src.port); printf(" destination mac addr: "); print_mac_addr(fp_mac_addr_dst.addr); newline(); - printf(" destination ip addr: %d.%d.%d.%d\n", - ((const unsigned char*)&fp_socket_dst.addr.addr)[0], - ((const unsigned char*)&fp_socket_dst.addr.addr)[1], - ((const unsigned char*)&fp_socket_dst.addr.addr)[2], - ((const unsigned char*)&fp_socket_dst.addr.addr)[3] - ); + printf(" destination ip addr: "); + print_ip_addr(&fp_socket_dst.addr); newline(); printf(" destination udp port: %d\n", fp_socket_dst.port); newline(); } @@ -217,14 +212,24 @@ void handle_udp_ctrl_packet( ******************************************************************/ case USRP2_CTRL_ID_GIVE_ME_YOUR_IP_ADDR_BRO: ctrl_data_out.id = USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE; - struct ip_addr ip_addr = get_my_ip_addr(); - memcpy(&ctrl_data_out.data.ip_addr, &ip_addr, sizeof(ip_addr)); + 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; - eth_mac_addr_t mac_addr = get_my_eth_mac_addr(); - memcpy(&ctrl_data_out.data.mac_addr, &mac_addr, sizeof(mac_addr)); + 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; case USRP2_CTRL_ID_GIVE_ME_YOUR_DBOARD_IDS_BRO: @@ -720,6 +725,7 @@ main(void) putstr("\nTxRx-NEWETH\n"); print_mac_addr(ethernet_mac_addr()->addr); newline(); + print_ip_addr(get_ip_addr()); newline(); ethernet_register_link_changed_callback(link_changed_callback); ethernet_init(); diff --git a/firmware/microblaze/include/usrp2_i2c_addr.h b/firmware/microblaze/include/usrp2_i2c_addr.h index 4111cdd55..46f5a7556 100644 --- a/firmware/microblaze/include/usrp2_i2c_addr.h +++ b/firmware/microblaze/include/usrp2_i2c_addr.h @@ -41,6 +41,7 @@ #define MBOARD_REV_LSB 0x00 #define MBOARD_REV_MSB 0x01 #define MBOARD_MAC_ADDR 0x02 +#define MBOARD_IP_ADDR 0x0C // format of daughterboard EEPROM diff --git a/firmware/microblaze/lib/ethernet.c b/firmware/microblaze/lib/ethernet.c index 5402a6c9f..757a36ce4 100644 --- a/firmware/microblaze/lib/ethernet.c +++ b/firmware/microblaze/lib/ethernet.c @@ -271,58 +271,100 @@ ethernet_init(void) } static bool -unprogrammed(const eth_mac_addr_t *t) +unprogrammed(const void *t, size_t len) { int i; + uint8_t *p = (uint8_t *)t; bool all_zeros = true; bool all_ones = true; - for (i = 0; i < 6; i++){ - all_zeros &= t->addr[i] == 0x00; - all_ones &= t->addr[i] == 0xff; + for (i = 0; i < len; i++){ + all_zeros &= p[i] == 0x00; + all_ones &= p[i] == 0xff; } return all_ones | all_zeros; } -static int8_t src_addr_initialized = false; -static eth_mac_addr_t src_addr = {{ +//////////////////// MAC Addr Stuff /////////////////////// + +static int8_t src_mac_addr_initialized = false; +static eth_mac_addr_t src_mac_addr = {{ 0x00, 0x50, 0xC2, 0x85, 0x3f, 0xff }}; const eth_mac_addr_t * ethernet_mac_addr(void) { - if (!src_addr_initialized){ // fetch from eeprom - src_addr_initialized = true; + if (!src_mac_addr_initialized){ // fetch from eeprom + src_mac_addr_initialized = true; // if we're simulating, don't read the EEPROM model, it's REALLY slow - if (hwconfig_simulation_p()) - return &src_addr; + if (hwconfig_simulation_p()) + return &src_mac_addr; eth_mac_addr_t tmp; - bool ok = eeprom_read(I2C_ADDR_MBOARD, MBOARD_MAC_ADDR, &tmp.addr[0], 6); - if (!ok || unprogrammed(&tmp)){ + bool ok = eeprom_read(I2C_ADDR_MBOARD, MBOARD_MAC_ADDR, &tmp, sizeof(tmp)); + if (!ok || unprogrammed(&tmp, sizeof(tmp))){ // use the default } else - src_addr = tmp; + src_mac_addr = tmp; } - return &src_addr; + return &src_mac_addr; } bool ethernet_set_mac_addr(const eth_mac_addr_t *t) { - bool ok = eeprom_write(I2C_ADDR_MBOARD, MBOARD_MAC_ADDR, &t->addr[0], 6); + bool ok = eeprom_write(I2C_ADDR_MBOARD, MBOARD_MAC_ADDR, &t, sizeof(eth_mac_addr_t)); if (ok){ - src_addr = *t; - src_addr_initialized = true; + src_mac_addr = *t; + src_mac_addr_initialized = true; eth_mac_set_addr(t); } return ok; } +//////////////////// IP Addr Stuff /////////////////////// + +static int8_t src_ip_addr_initialized = false; +static struct ip_addr src_ip_addr = { + (192 << 24 | 168 << 16 | 10 << 8 | 2 << 0) +}; + + +const struct ip_addr *get_ip_addr(void) +{ + if (!src_ip_addr_initialized){ // fetch from eeprom + src_ip_addr_initialized = true; + + // if we're simulating, don't read the EEPROM model, it's REALLY slow + if (hwconfig_simulation_p()) + return &src_ip_addr; + + struct ip_addr tmp; + bool ok = eeprom_read(I2C_ADDR_MBOARD, MBOARD_IP_ADDR, &tmp, sizeof(tmp)); + if (!ok || unprogrammed(&tmp, sizeof(tmp))){ + // use the default + } + else + src_ip_addr = tmp; + } + + return &src_ip_addr; +} + +bool set_ip_addr(const struct ip_addr *t){ + bool ok = eeprom_write(I2C_ADDR_MBOARD, MBOARD_IP_ADDR, &t, sizeof(struct ip_addr)); + if (ok){ + src_ip_addr = *t; + src_ip_addr_initialized = true; + } + + return ok; +} + int ethernet_check_errors(void) { diff --git a/firmware/microblaze/lib/ethernet.h b/firmware/microblaze/lib/ethernet.h index 70b7077c6..8c6d8b567 100644 --- a/firmware/microblaze/lib/ethernet.h +++ b/firmware/microblaze/lib/ethernet.h @@ -20,6 +20,7 @@ #define INCLUDED_ETHERNET_H #include +#include #include typedef void (*ethernet_link_changed_callback_t)(int speed); @@ -48,6 +49,16 @@ const eth_mac_addr_t *ethernet_mac_addr(void); */ bool ethernet_set_mac_addr(const eth_mac_addr_t *t); +/*! + * \returns IP address + */ +const struct ip_addr *get_ip_addr(void); + +/*! + * \brief write ip address to eeprom and begin using it + */ +bool set_ip_addr(const struct ip_addr *t); + /* * \brief read RMON regs and return error mask diff --git a/host/apps/CMakeLists.txt b/host/apps/CMakeLists.txt index f4428f958..4deb41965 100644 --- a/host/apps/CMakeLists.txt +++ b/host/apps/CMakeLists.txt @@ -16,7 +16,8 @@ # ADD_EXECUTABLE(discover_usrps discover_usrps.cpp) - TARGET_LINK_LIBRARIES(discover_usrps uhd) - INSTALL(TARGETS discover_usrps RUNTIME DESTINATION ${RUNTIME_DIR}) + +ADD_EXECUTABLE(usrp2_burner usrp2_burner.cpp) +TARGET_LINK_LIBRARIES(usrp2_burner uhd) diff --git a/host/apps/usrp2_burner.cpp b/host/apps/usrp2_burner.cpp new file mode 100644 index 000000000..08ec8daf9 --- /dev/null +++ b/host/apps/usrp2_burner.cpp @@ -0,0 +1,83 @@ +// +// 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 + +namespace po = boost::program_options; + +int main(int argc, char *argv[]){ + po::options_description desc("Allowed options"); + desc.add_options() + ("help", "help message") + ("addr", po::value(), "resolvable network address") + ("new-ip", po::value(), "new ip address (optional)") + ("new-mac", po::value(), "new mac address (optional)") + ; + + 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("USRP2 Burner %s") % desc << std::endl; + return ~0; + } + + //load the options into the address + uhd::device_addr_t device_addr; + if (vm.count("addr")){ + device_addr["addr"] = vm["addr"].as(); + } + else{ + std::cerr << "Error: missing addr option" << std::endl; + return ~0; + } + + //create a usrp2 device + uhd::device::sptr u2_dev = uhd::usrp::usrp2::make(device_addr); + //FIXME usees the default mboard for now (until the mimo link is supported) + wax::obj u2_mb = (*u2_dev)[uhd::DEVICE_PROP_MBOARD]; + + //try to set the new ip (if provided) + if (vm.count("new-ip")){ + std::cout << "Burning a new ip address into the usrp2 eeprom:" << std::endl; + std::string old_ip = u2_mb[std::string("ip-addr")].as(); + std::cout << boost::format(" Old IP Address: %s") % old_ip << std::endl; + std::string new_ip = vm["new-ip"].as(); + std::cout << boost::format(" New IP Address: %s") % new_ip << std::endl; + u2_mb[std::string("ip-addr")] = new_ip; + std::cout << " Done" << std::endl; + } + + //try to set the new mac (if provided) + if (vm.count("new-mac")){ + std::cout << "Burning a new mac address into the usrp2 eeprom:" << std::endl; + std::string old_mac = u2_mb[std::string("mac-addr")].as(); + std::cout << boost::format(" Old MAC Address: %s") % old_mac << std::endl; + std::string new_mac = vm["new-mac"].as(); + std::cout << boost::format(" New MAC Address: %s") % new_mac << std::endl; + u2_mb[std::string("mac-addr")] = new_mac; + std::cout << " Done" << std::endl; + } + + return 0; +} diff --git a/host/include/uhd/wax.hpp b/host/include/uhd/wax.hpp index 1d5054351..4fd54ba14 100644 --- a/host/include/uhd/wax.hpp +++ b/host/include/uhd/wax.hpp @@ -124,6 +124,17 @@ namespace wax{ */ const std::type_info & type(void) const; + /*! + * Cast this obj into the desired type. + * Usage myobj.as() + * + * \return an object of the desired type + * \throw wax::bad_cast when the cast fails + */ + template T as(void) const{ + return boost::any_cast(resolve()); + } + private: //private interface (override in subclasses) virtual void get(const obj &, obj &); @@ -137,7 +148,6 @@ namespace wax{ * \return a boost any type with contents */ boost::any resolve(void) const; - template friend T cast(const obj &); //private contents of this obj boost::any _contents; @@ -159,7 +169,7 @@ namespace wax{ * \throw wax::bad_cast when the cast fails */ template T cast(const obj &val){ - return boost::any_cast(val.resolve()); + return val.as(); } } //namespace wax -- cgit v1.2.3 From fc40ff2f1327d01c72c4d7dbc07a14e473251981 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 15 Mar 2010 17:43:10 -0700 Subject: Replaced uses of wax:cast with the templated as method (like in boost program options). --- host/include/uhd/gain_handler.hpp | 2 +- host/include/uhd/props.hpp | 2 +- host/include/uhd/wax.hpp | 43 ++++++++++------------------- host/lib/gain_handler.cpp | 6 ++--- host/lib/simple_device.cpp | 54 ++++++++++++++++++------------------- host/lib/usrp/dboard/basic.cpp | 16 +++++------ host/lib/usrp/usrp2/dboard_impl.cpp | 4 +-- host/lib/usrp/usrp2/dsp_impl.cpp | 24 ++++++++--------- host/lib/usrp/usrp2/mboard_impl.cpp | 26 +++++++++--------- host/lib/usrp/usrp2/usrp2_impl.cpp | 2 +- host/lib/wax.cpp | 6 ++--- host/test/gain_handler_test.cpp | 12 ++++----- host/test/wax_test.cpp | 15 ++++++----- 13 files changed, 99 insertions(+), 113 deletions(-) diff --git a/host/include/uhd/gain_handler.hpp b/host/include/uhd/gain_handler.hpp index 2d3f8a3f4..a71d63c84 100644 --- a/host/include/uhd/gain_handler.hpp +++ b/host/include/uhd/gain_handler.hpp @@ -74,7 +74,7 @@ public: */ template static bool is_equal(const wax::obj &a, const wax::obj &b){ try{ - return wax::cast(a) == wax::cast(b); + return a.as() == b.as(); } catch(const wax::bad_cast &){ return false; diff --git a/host/include/uhd/props.hpp b/host/include/uhd/props.hpp index f2ba1769f..0dddba647 100644 --- a/host/include/uhd/props.hpp +++ b/host/include/uhd/props.hpp @@ -57,7 +57,7 @@ namespace uhd{ */ inline named_prop_t extract_named_prop(const wax::obj &key, const std::string &name = ""){ if (key.type() == typeid(named_prop_t)){ - return wax::cast(key); + return key.as(); } return named_prop_t(key, name); } diff --git a/host/include/uhd/wax.hpp b/host/include/uhd/wax.hpp index 4fd54ba14..0291a06b7 100644 --- a/host/include/uhd/wax.hpp +++ b/host/include/uhd/wax.hpp @@ -19,31 +19,34 @@ #define INCLUDED_WAX_HPP #include -#include /*! * WAX - it's a metaphor! * - * The WAX framework allows object to have generic/anyobj properties. + * The WAX framework allows an object to have generic/anyobj properties. * These properties can be addressed through generic/anyobj identifiers. - * A property of a WAX object may even be another WAX object. * - * When a property is a WAX object, the returned value must be an obj pointer. - * A WAX object provides two objs of pointers: obj::ptr and obj::sptr. - * The choice of pointer vs smart pointer depends on the owner of the memory. + * The WAX object itself is an anytype container much like boost::any. + * To retrieve the value of the appropriate type, use my_obj.as(). * * Proprties may be referenced though the [] overloaded operator. * The [] operator returns a special proxy that allows for assigment. * Also, the [] operators may be chained as in the folowing examples: - * my_obj[prop1][prop2][prop3] = value - * value = my_obj[prop1][prop2][prop3] + * my_obj[prop1][prop2][prop3] = value; + * value = my_obj[prop1][prop2][prop3].as(); * - * Any value returned from an access operation is of wax::obj. - * To use this value, it must be cast with wax::cast(value). + * Property nesting occurs when a WAX object gets another object's link. + * This special link is obtained through a call to my_obj.get_link(). */ namespace wax{ + /*! + * The wax::bad cast will be thrown when + * cast is called with the wrong typeid. + */ + typedef boost::bad_any_cast bad_cast; + /*! * WAX object base class: * @@ -126,7 +129,7 @@ namespace wax{ /*! * Cast this obj into the desired type. - * Usage myobj.as() + * Usage: myobj.as() * * \return an object of the desired type * \throw wax::bad_cast when the cast fails @@ -154,24 +157,6 @@ namespace wax{ }; - /*! - * The wax::bad cast will be thrown when - * cast is called with the wrong typeid. - */ - typedef boost::bad_any_cast bad_cast; - - /*! - * Cast a wax::obj into the desired obj. - * Usage wax::cast(my_value). - * - * \param val the obj to cast - * \return an object of the desired type - * \throw wax::bad_cast when the cast fails - */ - template T cast(const obj &val){ - return val.as(); - } - } //namespace wax #endif /* INCLUDED_WAX_HPP */ diff --git a/host/lib/gain_handler.cpp b/host/lib/gain_handler.cpp index 7eb87558c..847bc0528 100644 --- a/host/lib/gain_handler.cpp +++ b/host/lib/gain_handler.cpp @@ -48,7 +48,7 @@ private: gain_t get_overall_gain_val(void); gain_range_t get_overall_gain_range(void); template T get_named_prop(const wax::obj &prop, const std::string &name){ - return wax::cast(_link[named_prop_t(prop, name)]); + return _link[named_prop_t(prop, name)].as(); } }; @@ -85,7 +85,7 @@ gain_handler_impl::~gain_handler_impl(void){ } prop_names_t gain_handler_impl::get_gain_names(void){ - return wax::cast(_link[_props.names]); + return _link[_props.names].as(); } gain_t gain_handler_impl::get_overall_gain_val(void){ @@ -145,7 +145,7 @@ bool gain_handler_impl::intercept_set(const wax::obj &key_, const wax::obj &val) //not a gain value key... dont handle if (not _is_equal(key, _props.value)) return false; - gain_t gain_val = wax::cast(val); + gain_t gain_val = val.as(); //not a wildcard... dont handle (but check name and range) if (name != ""){ diff --git a/host/lib/simple_device.cpp b/host/lib/simple_device.cpp index ac83ffaed..62a38cb79 100644 --- a/host/lib/simple_device.cpp +++ b/host/lib/simple_device.cpp @@ -42,15 +42,15 @@ static tune_result_t tune( bool is_tx ){ wax::obj subdev_freq_proxy = subdev[SUBDEV_PROP_FREQ]; - bool subdev_quadrature = wax::cast(subdev[SUBDEV_PROP_QUADRATURE]); - bool subdev_spectrum_inverted = wax::cast(subdev[SUBDEV_PROP_SPECTRUM_INVERTED]); + bool subdev_quadrature = subdev[SUBDEV_PROP_QUADRATURE].as(); + bool subdev_spectrum_inverted = subdev[SUBDEV_PROP_SPECTRUM_INVERTED].as(); wax::obj dxc_freq_proxy = dxc[std::string("freq")]; - double dxc_sample_rate = wax::cast(dxc[std::string("rate")]); + double dxc_sample_rate = dxc[std::string("rate")].as(); // Ask the d'board to tune as closely as it can to target_freq+lo_offset double target_inter_freq = target_freq + lo_offset; subdev_freq_proxy = target_inter_freq; - double actual_inter_freq = wax::cast(subdev_freq_proxy); + double actual_inter_freq = subdev_freq_proxy.as(); // Calculate the DDC setting that will downconvert the baseband from the // daughterboard to our target frequency. @@ -77,7 +77,7 @@ static tune_result_t tune( target_dxc_freq *= (is_tx)? -1.0 : +1.0; dxc_freq_proxy = target_dxc_freq; - double actual_dxc_freq = wax::cast(dxc_freq_proxy); + double actual_dxc_freq = dxc_freq_proxy.as(); //return some kind of tune result tuple/struct tune_result_t tune_result; @@ -117,8 +117,8 @@ device_addr_t args_to_device_addr(const std::string &args){ static std::vector get_xx_rates(wax::obj decerps, wax::obj rate){ std::vector rates; - BOOST_FOREACH(size_t decerp, wax::cast >(decerps)){ - rates.push_back(wax::cast(rate)/decerp); + BOOST_FOREACH(size_t decerp, decerps.as >()){ + rates.push_back(rate.as()/decerp); } return rates; } @@ -146,7 +146,7 @@ public: } std::string get_name(void){ - return wax::cast(_mboard[MBOARD_PROP_NAME]); + return _mboard[MBOARD_PROP_NAME].as(); } /******************************************************************* @@ -157,21 +157,21 @@ public: } bool get_streaming(void){ - return wax::cast(_rx_ddc[std::string("enabled")]); + return _rx_ddc[std::string("enabled")].as(); } /******************************************************************* * RX methods ******************************************************************/ void set_rx_rate(double rate){ - double samp_rate = wax::cast(_rx_ddc[std::string("rate")]); + double samp_rate = _rx_ddc[std::string("rate")].as(); assert_has(get_rx_rates(), rate, "simple device rx rate"); _rx_ddc[std::string("decim")] = size_t(samp_rate/rate); } double get_rx_rate(void){ - double samp_rate = wax::cast(_rx_ddc[std::string("rate")]); - size_t decim = wax::cast(_rx_ddc[std::string("decim")]); + double samp_rate = _rx_ddc[std::string("rate")].as(); + size_t decim = _rx_ddc[std::string("decim")].as(); return samp_rate/decim; } @@ -182,7 +182,7 @@ public: tune_result_t set_rx_freq(double target_freq){ double lo_offset = 0.0; //if the local oscillator will be in the passband, use an offset - if (wax::cast(_rx_subdev[SUBDEV_PROP_LO_INTERFERES])){ + if (_rx_subdev[SUBDEV_PROP_LO_INTERFERES].as()){ lo_offset = get_rx_rate()*2.0; } return tune(target_freq, lo_offset, _rx_subdev, _rx_ddc, false/* not tx */); @@ -191,7 +191,7 @@ public: std::vector get_rx_freq_range(void){ std::vector range(2); boost::tie(range[0], range[1]) = \ - wax::cast(_rx_subdev[SUBDEV_PROP_FREQ_RANGE]); + _rx_subdev[SUBDEV_PROP_FREQ_RANGE].as(); return range; } @@ -200,13 +200,13 @@ public: } float get_rx_gain(void){ - return wax::cast(_rx_subdev[SUBDEV_PROP_GAIN]); + return _rx_subdev[SUBDEV_PROP_GAIN].as(); } std::vector get_rx_gain_range(void){ std::vector range(3); boost::tie(range[0], range[1], range[2]) = \ - wax::cast(_rx_subdev[SUBDEV_PROP_GAIN_RANGE]); + _rx_subdev[SUBDEV_PROP_GAIN_RANGE].as(); return range; } @@ -215,25 +215,25 @@ public: } std::string get_rx_antenna(void){ - return wax::cast(_rx_subdev[SUBDEV_PROP_ANTENNA]); + return _rx_subdev[SUBDEV_PROP_ANTENNA].as(); } std::vector get_rx_antennas(void){ - return wax::cast >(_rx_subdev[SUBDEV_PROP_ANTENNA_NAMES]); + return _rx_subdev[SUBDEV_PROP_ANTENNA_NAMES].as >(); } /******************************************************************* * TX methods ******************************************************************/ void set_tx_rate(double rate){ - double samp_rate = wax::cast(_tx_duc[std::string("rate")]); + double samp_rate = _tx_duc[std::string("rate")].as(); assert_has(get_tx_rates(), rate, "simple device tx rate"); _tx_duc[std::string("interp")] = size_t(samp_rate/rate); } double get_tx_rate(void){ - double samp_rate = wax::cast(_tx_duc[std::string("rate")]); - size_t interp = wax::cast(_tx_duc[std::string("interp")]); + double samp_rate = _tx_duc[std::string("rate")].as(); + size_t interp = _tx_duc[std::string("interp")].as(); return samp_rate/interp; } @@ -244,7 +244,7 @@ public: tune_result_t set_tx_freq(double target_freq){ double lo_offset = 0.0; //if the local oscillator will be in the passband, use an offset - if (wax::cast(_tx_subdev[SUBDEV_PROP_LO_INTERFERES])){ + if (_tx_subdev[SUBDEV_PROP_LO_INTERFERES].as()){ lo_offset = get_tx_rate()*2.0; } return tune(target_freq, lo_offset, _tx_subdev, _tx_duc, true/* is tx */); @@ -253,7 +253,7 @@ public: std::vector get_tx_freq_range(void){ std::vector range(2); boost::tie(range[0], range[1]) = \ - wax::cast(_tx_subdev[SUBDEV_PROP_FREQ_RANGE]); + _tx_subdev[SUBDEV_PROP_FREQ_RANGE].as(); return range; } @@ -262,13 +262,13 @@ public: } float get_tx_gain(void){ - return wax::cast(_tx_subdev[SUBDEV_PROP_GAIN]); + return _tx_subdev[SUBDEV_PROP_GAIN].as(); } std::vector get_tx_gain_range(void){ std::vector range(3); boost::tie(range[0], range[1], range[2]) = \ - wax::cast(_tx_subdev[SUBDEV_PROP_GAIN_RANGE]); + _tx_subdev[SUBDEV_PROP_GAIN_RANGE].as(); return range; } @@ -277,11 +277,11 @@ public: } std::string get_tx_antenna(void){ - return wax::cast(_tx_subdev[SUBDEV_PROP_ANTENNA]); + return _tx_subdev[SUBDEV_PROP_ANTENNA].as(); } std::vector get_tx_antennas(void){ - return wax::cast >(_tx_subdev[SUBDEV_PROP_ANTENNA_NAMES]); + return _tx_subdev[SUBDEV_PROP_ANTENNA_NAMES].as >(); } private: diff --git a/host/lib/usrp/dboard/basic.cpp b/host/lib/usrp/dboard/basic.cpp index e719950e8..095b77ce1 100644 --- a/host/lib/usrp/dboard/basic.cpp +++ b/host/lib/usrp/dboard/basic.cpp @@ -98,7 +98,7 @@ void basic_rx::rx_get(const wax::obj &key_, wax::obj &val){ boost::tie(key, name) = extract_named_prop(key_); //handle the get request conditioned on the key - switch(wax::cast(key)){ + switch(key.as()){ case SUBDEV_PROP_NAME: val = std::string(str(boost::format("%s:%s") % dboard_id::to_string(get_rx_id()) @@ -159,14 +159,14 @@ void basic_rx::rx_set(const wax::obj &key_, const wax::obj &val){ boost::tie(key, name) = extract_named_prop(key_); //handle the get request conditioned on the key - switch(wax::cast(key)){ + switch(key.as()){ case SUBDEV_PROP_GAIN: - ASSERT_THROW(wax::cast(val) == gain_t(0)); + ASSERT_THROW(val.as() == gain_t(0)); return; case SUBDEV_PROP_ANTENNA: - ASSERT_THROW(wax::cast(val) == std::string("")); + ASSERT_THROW(val.as() == std::string("")); return; case SUBDEV_PROP_ENABLED: @@ -207,7 +207,7 @@ void basic_tx::tx_get(const wax::obj &key_, wax::obj &val){ boost::tie(key, name) = extract_named_prop(key_); //handle the get request conditioned on the key - switch(wax::cast(key)){ + switch(key.as()){ case SUBDEV_PROP_NAME: val = dboard_id::to_string(get_tx_id()); return; @@ -265,14 +265,14 @@ void basic_tx::tx_set(const wax::obj &key_, const wax::obj &val){ boost::tie(key, name) = extract_named_prop(key_); //handle the get request conditioned on the key - switch(wax::cast(key)){ + switch(key.as()){ case SUBDEV_PROP_GAIN: - ASSERT_THROW(wax::cast(val) == gain_t(0)); + ASSERT_THROW(val.as() == gain_t(0)); return; case SUBDEV_PROP_ANTENNA: - ASSERT_THROW(wax::cast(val) == std::string("")); + ASSERT_THROW(val.as() == std::string("")); return; case SUBDEV_PROP_ENABLED: diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp index da05c3241..6d957436e 100644 --- a/host/lib/usrp/usrp2/dboard_impl.cpp +++ b/host/lib/usrp/usrp2/dboard_impl.cpp @@ -71,7 +71,7 @@ void usrp2_impl::rx_dboard_get(const wax::obj &key_, wax::obj &val){ boost::tie(key, name) = extract_named_prop(key_); //handle the get request conditioned on the key - switch(wax::cast(key)){ + switch(key.as()){ case DBOARD_PROP_NAME: val = std::string("usrp2 dboard (rx unit)"); return; @@ -101,7 +101,7 @@ void usrp2_impl::tx_dboard_get(const wax::obj &key_, wax::obj &val){ boost::tie(key, name) = extract_named_prop(key_); //handle the get request conditioned on the key - switch(wax::cast(key)){ + switch(key.as()){ case DBOARD_PROP_NAME: val = std::string("usrp2 dboard (tx unit)"); return; diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index cb7f58ec8..7520c1757 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -102,7 +102,7 @@ void usrp2_impl::update_ddc_enabled(void){ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){ //handle the case where the key is an expected dsp property if (key.type() == typeid(dsp_prop_t)){ - switch(wax::cast(key)){ + switch(key.as()){ case DSP_PROP_NAME: val = std::string("usrp2 ddc0"); return; @@ -123,7 +123,7 @@ void usrp2_impl::ddc_get(const wax::obj &key, wax::obj &val){ } //handle string-based properties specific to this dsp - std::string key_name = wax::cast(key); + std::string key_name = key.as(); if (key_name == "rate"){ val = get_master_clock_freq(); return; @@ -152,9 +152,9 @@ 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){ //handle string-based properties specific to this dsp - std::string key_name = wax::cast(key); + std::string key_name = key.as(); if (key_name == "decim"){ - size_t new_decim = wax::cast(val); + size_t new_decim = val.as(); assert_has( _allowed_decim_and_interp_rates, new_decim, "usrp2 decimation" @@ -164,7 +164,7 @@ void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){ return; } else if (key_name == "freq"){ - freq_t new_freq = wax::cast(val); + freq_t new_freq = val.as(); ASSERT_THROW(new_freq <= get_master_clock_freq()/2.0); ASSERT_THROW(new_freq >= -get_master_clock_freq()/2.0); _ddc_freq = new_freq; //shadow @@ -172,13 +172,13 @@ void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){ return; } else if (key_name == "enabled"){ - bool new_enabled = wax::cast(val); + bool new_enabled = val.as(); _ddc_enabled = new_enabled; //shadow update_ddc_enabled(); return; } else if (key_name == "stream_at"){ - time_spec_t new_stream_at = wax::cast(val); + time_spec_t new_stream_at = val.as(); _ddc_stream_at = new_stream_at; //shadow //update_ddc_enabled(); //dont update from here return; @@ -236,7 +236,7 @@ void usrp2_impl::update_duc_config(void){ void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){ //handle the case where the key is an expected dsp property if (key.type() == typeid(dsp_prop_t)){ - switch(wax::cast(key)){ + switch(key.as()){ case DSP_PROP_NAME: val = std::string("usrp2 duc0"); return; @@ -255,7 +255,7 @@ void usrp2_impl::duc_get(const wax::obj &key, wax::obj &val){ } //handle string-based properties specific to this dsp - std::string key_name = wax::cast(key); + std::string key_name = key.as(); if (key_name == "rate"){ val = get_master_clock_freq(); return; @@ -280,9 +280,9 @@ 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){ //handle string-based properties specific to this dsp - std::string key_name = wax::cast(key); + std::string key_name = key.as(); if (key_name == "interp"){ - size_t new_interp = wax::cast(val); + size_t new_interp = val.as(); assert_has( _allowed_decim_and_interp_rates, new_interp, "usrp2 interpolation" @@ -292,7 +292,7 @@ void usrp2_impl::duc_set(const wax::obj &key, const wax::obj &val){ return; } else if (key_name == "freq"){ - freq_t new_freq = wax::cast(val); + freq_t new_freq = val.as(); ASSERT_THROW(new_freq <= get_master_clock_freq()/2.0); ASSERT_THROW(new_freq >= -get_master_clock_freq()/2.0); _duc_freq = new_freq; //shadow diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index b66de8262..4b15c7f3e 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -91,7 +91,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ //handle the other props if (key.type() == typeid(std::string)){ - if (wax::cast(key) == "mac-addr"){ + 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); @@ -105,7 +105,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ return; } - if (wax::cast(key) == "ip-addr"){ + 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); @@ -121,7 +121,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ } //handle the get request conditioned on the key - switch(wax::cast(key)){ + switch(key.as()){ case MBOARD_PROP_NAME: val = std::string("usrp2 mboard"); return; @@ -208,11 +208,11 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){ //handle the other props if (key.type() == typeid(std::string)){ - if (wax::cast(key) == "mac-addr"){ + 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(wax::cast(val)); + mac_addr_t mac_addr(val.as()); std::memcpy(out_data.data.mac_addr, &mac_addr, sizeof(mac_addr_t)); //send and recv @@ -221,11 +221,11 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){ return; } - if (wax::cast(key) == "ip-addr"){ + 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(wax::cast(val)).to_ulong()); + 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 = ctrl_send_and_recv(out_data); @@ -235,10 +235,10 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){ } //handle the get request conditioned on the key - switch(wax::cast(key)){ + switch(key.as()){ case MBOARD_PROP_PPS_SOURCE:{ - std::string name = wax::cast(val); + std::string name = val.as(); assert_has(_pps_source_dict.get_keys(), name, "usrp2 pps source"); _pps_source = name; //shadow update_clock_config(); @@ -246,7 +246,7 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){ return; case MBOARD_PROP_PPS_POLARITY:{ - std::string name = wax::cast(val); + std::string name = val.as(); assert_has(_pps_polarity_dict.get_keys(), name, "usrp2 pps polarity"); _pps_polarity = name; //shadow update_clock_config(); @@ -254,7 +254,7 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){ return; case MBOARD_PROP_REF_SOURCE:{ - std::string name = wax::cast(val); + std::string name = val.as(); assert_has(_ref_source_dict.get_keys(), name, "usrp2 reference source"); _ref_source = name; //shadow update_clock_config(); @@ -262,12 +262,12 @@ void usrp2_impl::mboard_set(const wax::obj &key, const wax::obj &val){ return; case MBOARD_PROP_TIME_NOW:{ - set_time_spec(wax::cast(val), true); + set_time_spec(val.as(), true); return; } case MBOARD_PROP_TIME_NEXT_PPS:{ - set_time_spec(wax::cast(val), false); + set_time_spec(val.as(), false); return; } diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 850a738d4..22b7e109f 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -184,7 +184,7 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){ boost::tie(key, name) = extract_named_prop(key_); //handle the get request conditioned on the key - switch(wax::cast(key)){ + switch(key.as()){ case DEVICE_PROP_NAME: val = std::string("usrp2 device"); return; diff --git a/host/lib/wax.cpp b/host/lib/wax.cpp index 0348d9a66..0e2e82a3a 100644 --- a/host/lib/wax.cpp +++ b/host/lib/wax.cpp @@ -39,7 +39,7 @@ public: wax::obj & operator()(void) const{ //recursively resolve link args to get at original pointer if (_obj_ptr->type() == typeid(link_args_t)){ - return wax::cast(*_obj_ptr)(); + return _obj_ptr->as()(); } return *const_cast(_obj_ptr); } @@ -61,7 +61,7 @@ public: _obj_link = obj_ptr->get_link(); } wax::obj & operator()(void) const{ - return wax::cast(_obj_link)(); + return _obj_link.as()(); } const wax::obj & key(void) const{ return _key; @@ -94,7 +94,7 @@ wax::obj wax::obj::operator[](const obj &key){ obj val = resolve(); //check if its a special link and call if (val.type() == typeid(link_args_t)){ - return cast(val)()[key]; + return val.as()()[key]; } //unknown obj throw std::runtime_error("cannot use [] on non wax::obj link"); diff --git a/host/test/gain_handler_test.cpp b/host/test/gain_handler_test.cpp index 51497b741..a4005c0de 100644 --- a/host/test/gain_handler_test.cpp +++ b/host/test/gain_handler_test.cpp @@ -59,7 +59,7 @@ private: boost::tie(key, name) = extract_named_prop(key_); //handle the get request conditioned on the key - switch(wax::cast(key)){ + switch(key.as()){ case PROP_GAIN_VALUE: val = _gain_values[name]; return; @@ -81,9 +81,9 @@ private: boost::tie(key, name) = extract_named_prop(key_); //handle the get request conditioned on the key - switch(wax::cast(key)){ + switch(key.as()){ case PROP_GAIN_VALUE: - _gain_values[name] = wax::cast(val); + _gain_values[name] = val.as(); return; case PROP_GAIN_RANGE: @@ -103,14 +103,14 @@ BOOST_AUTO_TEST_CASE(test_gain_handler){ gainful_obj go0; BOOST_CHECK_THROW( - wax::cast(go0[named_prop_t(PROP_GAIN_VALUE, "fail")]), + go0[named_prop_t(PROP_GAIN_VALUE, "fail")].as(), std::exception ); std::cout << "verifying the overall min, max, step" << std::endl; gain_t gain_min, gain_max, gain_step; boost::tie(gain_min, gain_max, gain_step) = \ - wax::cast(go0[PROP_GAIN_RANGE]); + go0[PROP_GAIN_RANGE].as(); BOOST_CHECK_EQUAL(gain_min, gain_t(-10)); BOOST_CHECK_EQUAL(gain_max, gain_t(100)); BOOST_CHECK_EQUAL(gain_step, gain_t(1.5)); @@ -118,5 +118,5 @@ BOOST_AUTO_TEST_CASE(test_gain_handler){ std::cout << "verifying the overall gain" << std::endl; go0[named_prop_t(PROP_GAIN_VALUE, "g0")] = gain_t(-5); go0[named_prop_t(PROP_GAIN_VALUE, "g1")] = gain_t(30); - BOOST_CHECK_EQUAL(wax::cast(go0[PROP_GAIN_VALUE]), gain_t(25)); + BOOST_CHECK_EQUAL(go0[PROP_GAIN_VALUE].as(), gain_t(25)); } diff --git a/host/test/wax_test.cpp b/host/test/wax_test.cpp index e5e1adc25..b793b2690 100644 --- a/host/test/wax_test.cpp +++ b/host/test/wax_test.cpp @@ -17,14 +17,15 @@ #include #include +#include enum opt_a_t{OPTION_A_0, OPTION_A_1}; enum opt_b_t{OPTION_B_0, OPTION_B_1}; BOOST_AUTO_TEST_CASE(test_enums){ wax::obj opta = OPTION_A_0; - BOOST_CHECK_THROW(wax::cast(opta), wax::bad_cast); - BOOST_CHECK_EQUAL(wax::cast(opta), OPTION_A_0); + BOOST_CHECK_THROW(opta.as(), wax::bad_cast); + BOOST_CHECK_EQUAL(opta.as(), OPTION_A_0); } /*********************************************************************** @@ -48,14 +49,14 @@ public: } void get(const wax::obj &key, wax::obj &value){ if (d_subs.size() == 0){ - value = d_nums[wax::cast(key)]; + value = d_nums[key.as()]; }else{ - value = d_subs[wax::cast(key)].get_link(); + value = d_subs[key.as()].get_link(); } } void set(const wax::obj &key, const wax::obj &value){ if (d_subs.size() == 0){ - d_nums[wax::cast(key)] = wax::cast(value); + d_nums[key.as()] = value.as(); }else{ throw std::runtime_error("cant set to a wax demo with sub demos"); } @@ -81,7 +82,7 @@ BOOST_AUTO_TEST_CASE(test_set_get){ float val = i * j * k + i + j + k; //std::cout << i << " " << j << " " << k << std::endl; wd[i][j][k] = val; - BOOST_CHECK_EQUAL(val, wax::cast(wd[i][j][k])); + BOOST_CHECK_EQUAL(val, wd[i][j][k].as()); } } } @@ -94,5 +95,5 @@ BOOST_AUTO_TEST_CASE(test_proxy){ std::cout << "assign proxy" << std::endl; wax::obj a = p[size_t(0)]; - BOOST_CHECK_EQUAL(wax::cast(a), float(5)); + BOOST_CHECK_EQUAL(a.as(), float(5)); } -- cgit v1.2.3