From d42e588d76efc41d18dabc75027347fe123904d1 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 22 Feb 2010 11:42:32 -0800 Subject: Moved the udp implementation guts into the cpp file --- host/lib/usrp/usrp2/usrp2_impl.cpp | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) (limited to 'host/lib/usrp/usrp2/usrp2_impl.cpp') diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 2b4e8fe39..f44964394 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -33,17 +33,18 @@ 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); - uhd::transport::udp udp_transport(hint["addr"], ctrl_port, true); + transport::udp::sptr udp_transport = \ + transport::udp::make(hint["addr"], ctrl_port, true); //send a hello control packet usrp2_ctrl_data_t ctrl_data_out; 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))); + 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; while(true){ - uhd::shared_iovec iov = udp_transport.recv(); + uhd::shared_iovec iov = udp_transport->recv(); //std::cout << boost::asio::buffer_size(buff) << "\n"; if (iov.len < sizeof(usrp2_ctrl_data_t)){ //sleep a little so we dont burn cpu @@ -72,21 +73,17 @@ uhd::device_addrs_t usrp2::discover(const device_addr_t &hint){ /*********************************************************************** * Make **********************************************************************/ +#define num2str(num) (boost::lexical_cast(num)) + device::sptr usrp2::make(const device_addr_t &device_addr){ //create a control transport - uhd::transport::udp::sptr ctrl_transport( - new uhd::transport::udp( - device_addr["addr"], - boost::lexical_cast(USRP2_UDP_CTRL_PORT) - ) + transport::udp::sptr ctrl_transport = transport::udp::make( + device_addr["addr"], num2str(USRP2_UDP_CTRL_PORT) ); //create a data transport - uhd::transport::udp::sptr data_transport( - new uhd::transport::udp( - device_addr["addr"], - boost::lexical_cast(USRP2_UDP_DATA_PORT) - ) + transport::udp::sptr data_transport = transport::udp::make( + device_addr["addr"], num2str(USRP2_UDP_DATA_PORT) ); //create the usrp2 implementation guts @@ -99,8 +96,8 @@ device::sptr usrp2::make(const device_addr_t &device_addr){ * Structors **********************************************************************/ usrp2_impl::usrp2_impl( - uhd::transport::udp::sptr ctrl_transport, - uhd::transport::udp::sptr data_transport + transport::udp::sptr ctrl_transport, + transport::udp::sptr data_transport ){ _ctrl_transport = ctrl_transport; _data_transport = data_transport; @@ -121,9 +118,6 @@ usrp2_impl::usrp2_impl( //init the mboard mboard_init(); - //init the tx and rx dboards - dboard_init(); - //init the ddc init_ddc_config(); @@ -132,6 +126,10 @@ usrp2_impl::usrp2_impl( //initialize the clock configuration init_clock_config(); + + //init the tx and rx dboards (do last) + dboard_init(); + } usrp2_impl::~usrp2_impl(void){ -- cgit v1.2.3 From 6b7c53985c09a8d74e9bfd9c6b37948d458b2c44 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Mon, 22 Feb 2010 18:47:05 -0800 Subject: Work on the io interface for a device (and some implementation work in usrp2). Modified the udp transport to reflect some of these changes. Got the fw compiling again, and it will not set data to true for small payloads (configuration ones). --- firmware/microblaze/apps/Makefile.am | 2 +- firmware/microblaze/apps/txrx.c | 5 ++- host/CMakeLists.txt | 9 +++++ host/include/uhd/CMakeLists.txt | 1 + host/include/uhd/device.hpp | 33 +++++++++++++--- host/include/uhd/metadata.hpp | 47 +++++++++++++++++++++++ host/include/uhd/transport/udp.hpp | 17 ++++++++- host/lib/transport/udp.cpp | 20 ++++++---- host/lib/usrp/usrp2/usrp2_impl.cpp | 74 ++++++++++++++++++++++++++++++++++-- host/lib/usrp/usrp2/usrp2_impl.hpp | 4 +- 10 files changed, 189 insertions(+), 23 deletions(-) create mode 100644 host/include/uhd/metadata.hpp (limited to 'host/lib/usrp/usrp2/usrp2_impl.cpp') diff --git a/firmware/microblaze/apps/Makefile.am b/firmware/microblaze/apps/Makefile.am index 6d993ef8c..ff426cf8c 100644 --- a/firmware/microblaze/apps/Makefile.am +++ b/firmware/microblaze/apps/Makefile.am @@ -21,7 +21,7 @@ include $(top_srcdir)/Makefile.common LDADD = $(top_srcdir)/lib/libu2fw.a -AM_CFLAGS += -I$(top_srcdir)/../../host/lib/usrp/mboard +AM_CFLAGS += -I$(top_srcdir)/../../host/lib/usrp noinst_PROGRAMS = txrx.elf diff --git a/firmware/microblaze/apps/txrx.c b/firmware/microblaze/apps/txrx.c index 77c8e498c..16aa8eab2 100644 --- a/firmware/microblaze/apps/txrx.c +++ b/firmware/microblaze/apps/txrx.c @@ -159,7 +159,10 @@ void handle_udp_data_packet( unsigned char *payload, int payload_len ){ //TODO store the reply port - _is_data = true; + + //forward this data to the dsp when the payload is sufficient + //the small payload is used to give the device the udp source port + _is_data = payload_len > sizeof(uint32_t); } #define OTW_GPIO_BANK_TO_NUM(bank) \ diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index 70c04631b..30f4789a3 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -72,6 +72,15 @@ FIND_PACKAGE(Boost 1.36 REQUIRED INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS}) LINK_DIRECTORIES(${Boost_LIBRARY_DIRS}) +######################################################################## +# Setup Endianess +######################################################################## +INCLUDE(TestBigEndian) +TEST_BIG_ENDIAN(HAVE_BIG_ENDIAN) +IF(HAVE_BIG_ENDIAN) + ADD_DEFINITIONS("-DHAVE_BIG_ENDIAN=/* */") +ENDIF(HAVE_BIG_ENDIAN) + ######################################################################## # Create Uninstall Target ######################################################################## diff --git a/host/include/uhd/CMakeLists.txt b/host/include/uhd/CMakeLists.txt index 006c54f22..e87f74291 100644 --- a/host/include/uhd/CMakeLists.txt +++ b/host/include/uhd/CMakeLists.txt @@ -24,6 +24,7 @@ INSTALL(FILES device_addr.hpp dict.hpp gain_handler.hpp + metadata.hpp props.hpp shared_iovec.hpp time_spec.hpp diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index dfbfbd7c0..da58d4f85 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -20,13 +20,12 @@ #include #include +#include #include #include #include #include #include -#include -#include namespace uhd{ @@ -72,9 +71,33 @@ public: */ device_addr_t get_device_addr(void); - //the io interface - virtual void send_raw(const std::vector &) = 0; - virtual uhd::shared_iovec recv_raw(void) = 0; + /*! + * Send a buffer containing IF data with its metadata. + * + * \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) + * \return the number of bytes sent + */ + virtual size_t send( + const boost::asio::const_buffer &buff, + const metadata_t &metadata, + const std::string &type = "32fc" + ) = 0; + + /*! + * Receive a buffer containing IF data and its metadata. + * + * \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) + * \return the number of bytes received + */ + virtual size_t recv( + const boost::asio::mutable_buffer &buff, + metadata_t &metadata, + const std::string &type = "32fc" + ) = 0; }; } //namespace uhd diff --git a/host/include/uhd/metadata.hpp b/host/include/uhd/metadata.hpp new file mode 100644 index 000000000..43b91d1b0 --- /dev/null +++ b/host/include/uhd/metadata.hpp @@ -0,0 +1,47 @@ +// +// 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_METADATA_HPP +#define INCLUDED_UHD_METADATA_HPP + +#include + +namespace uhd{ + +/*! + * Metadata structure for describing the IF data. + * Includes stream ID, time specification, and burst flags. + * The receive routines will convert IF data headers into metadata. + * The send routines will convert the metadata to IF data headers. + */ +struct metadata_t{ + uint32_t stream_id; + time_spec_t time_spec; + bool start_of_burst; + bool end_of_burst; + + metadata_t(void){ + stream_id = 0; + time_spec = time_spec_t(); + start_of_burst = false; + end_of_burst = false; + } +}; + +} //namespace uhd + +#endif /* INCLUDED_UHD_METADATA_HPP */ diff --git a/host/include/uhd/transport/udp.hpp b/host/include/uhd/transport/udp.hpp index 554234b43..07d84e62a 100644 --- a/host/include/uhd/transport/udp.hpp +++ b/host/include/uhd/transport/udp.hpp @@ -41,18 +41,31 @@ public: /*! * 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 void send(const std::vector &buffs) = 0; + 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 void send(const boost::asio::const_buffer &buff) = 0; + 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 buff a mutable buffer to receive into + * \return the number of bytes received. + */ + virtual size_t recv(const boost::asio::mutable_buffer &buff) = 0; /*! * Receive a buffer. The memory is managed internally. + * Returns zero when data is not available. * Calling recv will invalidate the buffer of the previous recv. * \return a shared iovec with allocated memory */ diff --git a/host/lib/transport/udp.cpp b/host/lib/transport/udp.cpp index af60760a5..fca4dd7d6 100644 --- a/host/lib/transport/udp.cpp +++ b/host/lib/transport/udp.cpp @@ -17,7 +17,6 @@ #include #include -#include #include /*********************************************************************** @@ -30,8 +29,9 @@ public: ~udp_impl(void); //send/recv - void send(const std::vector &buffs); - void send(const boost::asio::const_buffer &buff); + size_t send(const std::vector &buffs); + size_t send(const boost::asio::const_buffer &buff); + size_t recv(const boost::asio::mutable_buffer &buff); uhd::shared_iovec recv(void); private: @@ -79,13 +79,17 @@ udp_impl::~udp_impl(void){ delete _socket; } -void udp_impl::send(const std::vector &buffs){ - _socket->send_to(buffs, _receiver_endpoint); +size_t udp_impl::send(const std::vector &buffs){ + return _socket->send_to(buffs, _receiver_endpoint); } -void udp_impl::send(const boost::asio::const_buffer &buff){ - std::vector buffs = boost::assign::list_of(buff); - send(buffs); +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 boost::asio::mutable_buffer &buff){ + if (_socket->available() == 0) return 0; + return _socket->receive_from(boost::asio::buffer(buff), _sender_endpoint); } uhd::shared_iovec udp_impl::recv(void){ diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index f44964394..47bf06aff 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -130,6 +130,10 @@ 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))); + } usrp2_impl::~usrp2_impl(void){ @@ -204,10 +208,72 @@ void usrp2_impl::set(const wax::obj &, const wax::obj &){ /*********************************************************************** * IO Interface **********************************************************************/ -void usrp2_impl::send_raw(const std::vector &){ - return; +static const float float_scale_factor = pow(2.0, 15); + +size_t usrp2_impl::send( + const boost::asio::const_buffer &buff, + const uhd::metadata_t &metadata, + const std::string &type +){ + if (type == "fc32"){ + //extract the buffer elements + const float *float_buff = boost::asio::buffer_cast(buff); + const size_t buff_len = boost::asio::buffer_size(buff)/sizeof(float); + + //convert floats into the shorts buffer + int16_t *shorts_buff = new int16_t[buff_len]; + for (size_t i = 0; i < buff_len; i++){ + shorts_buff[i] = float_buff[i]*float_scale_factor; + } + + //send from a buffer of shorts + size_t bytes_sent = send( + boost::asio::buffer(shorts_buff, buff_len*sizeof(int16_t)), + metadata, "sc16" + ); + + //cleanup + delete [] shorts_buff; + return bytes_sent; + } + + if (type == "sc16"){ + throw std::runtime_error("not implemented"); + } + + throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%s\"") % type)); } -uhd::shared_iovec usrp2_impl::recv_raw(void){ - throw std::runtime_error("not implemented"); +size_t usrp2_impl::recv( + const boost::asio::mutable_buffer &buff, + uhd::metadata_t &metadata, + const std::string &type +){ + if (type == "fc32"){ + //extract the buffer elements + float *float_buff = boost::asio::buffer_cast(buff); + const size_t buff_len = boost::asio::buffer_size(buff)/sizeof(float); + + //receive into a buffer of shorts + int16_t *shorts_buff = new int16_t[buff_len]; + size_t bytes_received = recv( + boost::asio::buffer(shorts_buff, buff_len*sizeof(int16_t)), + metadata, "sc16" + ); + + //convert floats into the shorts buffer + for (size_t i = 0; i < bytes_received/sizeof(int16_t); i++){ + float_buff[i] = shorts_buff[i]/float_scale_factor; + } + + //cleanup + delete [] shorts_buff; + return bytes_received; + } + + if (type == "sc16"){ + throw std::runtime_error("not implemented"); + } + + throw std::runtime_error(str(boost::format("usrp2 recv: cannot handle type \"%s\"") % type)); } diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 2545efd58..2476bcf1d 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -98,8 +98,8 @@ public: double get_master_clock_freq(void); //the io interface - void send_raw(const std::vector &); - uhd::shared_iovec recv_raw(void); + 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 &); private: //udp transports for control and data -- cgit v1.2.3 From 8050fda48d69f46788672a9ceaccd8d82500ac05 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Tue, 23 Feb 2010 16:27:49 -0800 Subject: Added IF data io handing within the usrp2 impl. It packs and unpacks vrt headers/metadata. NOT YET TESTED IN ANY WAY... --- host/include/uhd/CMakeLists.txt | 1 - host/include/uhd/device.hpp | 4 +- host/include/uhd/metadata.hpp | 4 + host/include/uhd/shared_iovec.hpp | 54 -------- host/include/uhd/transport/udp.hpp | 15 +-- host/lib/CMakeLists.txt | 2 +- host/lib/shared_iovec.cpp | 28 ---- host/lib/transport/udp.cpp | 20 +-- host/lib/usrp/usrp2/io_impl.cpp | 261 +++++++++++++++++++++++++++++++++++++ host/lib/usrp/usrp2/usrp2_impl.cpp | 95 ++------------ host/lib/usrp/usrp2/usrp2_impl.hpp | 5 + 11 files changed, 299 insertions(+), 190 deletions(-) delete mode 100644 host/include/uhd/shared_iovec.hpp delete mode 100644 host/lib/shared_iovec.cpp create mode 100644 host/lib/usrp/usrp2/io_impl.cpp (limited to 'host/lib/usrp/usrp2/usrp2_impl.cpp') diff --git a/host/include/uhd/CMakeLists.txt b/host/include/uhd/CMakeLists.txt index e87f74291..f4fb96786 100644 --- a/host/include/uhd/CMakeLists.txt +++ b/host/include/uhd/CMakeLists.txt @@ -26,7 +26,6 @@ INSTALL(FILES gain_handler.hpp metadata.hpp props.hpp - shared_iovec.hpp time_spec.hpp utils.hpp wax.hpp diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index da58d4f85..596a98bc4 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -77,7 +77,7 @@ public: * \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) - * \return the number of bytes sent + * \return the number of samples sent */ virtual size_t send( const boost::asio::const_buffer &buff, @@ -91,7 +91,7 @@ public: * \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) - * \return the number of bytes received + * \return the number of samples received */ virtual size_t recv( const boost::asio::mutable_buffer &buff, diff --git a/host/include/uhd/metadata.hpp b/host/include/uhd/metadata.hpp index 43b91d1b0..70842e7bc 100644 --- a/host/include/uhd/metadata.hpp +++ b/host/include/uhd/metadata.hpp @@ -30,13 +30,17 @@ namespace uhd{ */ struct metadata_t{ uint32_t stream_id; + bool has_stream_id; time_spec_t time_spec; + bool has_time_spec; 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; } diff --git a/host/include/uhd/shared_iovec.hpp b/host/include/uhd/shared_iovec.hpp deleted file mode 100644 index a120e55d5..000000000 --- a/host/include/uhd/shared_iovec.hpp +++ /dev/null @@ -1,54 +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_SHARED_IOVEC_HPP -#define INCLUDED_UHD_SHARED_IOVEC_HPP - -#include -#include - -namespace uhd{ - -/*! - * A shared iovec contains a shared array and its length. - * Creating a new shared iovec allocates new memory. - * This memory is freed when all copies are destroyed. - */ -class shared_iovec{ -public: - /*! - * Create a shared iovec and allocate memory. - * \param len the length in bytes - */ - shared_iovec(size_t len=0); - - /*! - * Destroy a shared iovec. - * Will not free the memory unless this is the last copy. - */ - ~shared_iovec(void); - - void *base; - size_t len; - -private: - boost::shared_array _shared_array; -}; - -} //namespace uhd - -#endif /* INCLUDED_UHD_SHARED_IOVEC_HPP */ diff --git a/host/include/uhd/transport/udp.hpp b/host/include/uhd/transport/udp.hpp index 07d84e62a..8c6fb096f 100644 --- a/host/include/uhd/transport/udp.hpp +++ b/host/include/uhd/transport/udp.hpp @@ -18,7 +18,6 @@ #include #include #include -#include #ifndef INCLUDED_UHD_TRANSPORT_UDP_HPP #define INCLUDED_UHD_TRANSPORT_UDP_HPP @@ -58,18 +57,18 @@ public: /*! * Receive a buffer. Write into the memory provided. * Returns empty when data is not available. - * \param buff a mutable buffer to receive into + * \param buffs a vector of asio buffers * \return the number of bytes received. */ - virtual size_t recv(const boost::asio::mutable_buffer &buff) = 0; + virtual size_t recv(const std::vector &buffs) = 0; /*! - * Receive a buffer. The memory is managed internally. - * Returns zero when data is not available. - * Calling recv will invalidate the buffer of the previous recv. - * \return a shared iovec with allocated memory + * 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 uhd::shared_iovec recv(void) = 0; + virtual size_t recv(const boost::asio::mutable_buffer &buff) = 0; }; }} //namespace diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index 5cf334678..253f45614 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -20,7 +20,6 @@ SET(libuhd_sources device.cpp device_addr.cpp gain_handler.cpp - shared_iovec.cpp uhd.cpp wax.cpp transport/udp.cpp @@ -32,6 +31,7 @@ SET(libuhd_sources usrp/usrp2/dboard_impl.cpp usrp/usrp2/dboard_interface.cpp usrp/usrp2/dsp_impl.cpp + usrp/usrp2/io_impl.cpp usrp/usrp2/mboard_impl.cpp usrp/usrp2/usrp2_impl.cpp ) diff --git a/host/lib/shared_iovec.cpp b/host/lib/shared_iovec.cpp deleted file mode 100644 index 60062fbf0..000000000 --- a/host/lib/shared_iovec.cpp +++ /dev/null @@ -1,28 +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 - -uhd::shared_iovec::shared_iovec(size_t len_){ - _shared_array = boost::shared_array(new uint8_t[len_]); - base = _shared_array.get(); - len = len_; -} - -uhd::shared_iovec::~shared_iovec(void){ - /* NOP */ -} diff --git a/host/lib/transport/udp.cpp b/host/lib/transport/udp.cpp index fca4dd7d6..878f71410 100644 --- a/host/lib/transport/udp.cpp +++ b/host/lib/transport/udp.cpp @@ -31,8 +31,8 @@ public: //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); - uhd::shared_iovec recv(void); private: boost::asio::ip::udp::socket *_socket; @@ -87,20 +87,12 @@ 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 boost::asio::mutable_buffer &buff){ +size_t udp_impl::recv(const std::vector &buffs){ if (_socket->available() == 0) return 0; - return _socket->receive_from(boost::asio::buffer(buff), _sender_endpoint); + return _socket->receive_from(buffs, _sender_endpoint); } -uhd::shared_iovec udp_impl::recv(void){ - //allocate a buffer for the number of bytes available (could be zero) - uhd::shared_iovec iov(_socket->available()); - //call recv only if data is available - if (iov.len != 0){ - _socket->receive_from( - boost::asio::buffer(iov.base, iov.len), - _sender_endpoint - ); - } - return iov; +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/usrp/usrp2/io_impl.cpp b/host/lib/usrp/usrp2/io_impl.cpp new file mode 100644 index 000000000..fbea71f85 --- /dev/null +++ b/host/lib/usrp/usrp2/io_impl.cpp @@ -0,0 +1,261 @@ +// +// 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 "usrp2_impl.hpp" + +using namespace uhd; +using namespace uhd::usrp; + +/*********************************************************************** + * Constants + **********************************************************************/ +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; + +/*********************************************************************** + * Helper Functions + **********************************************************************/ + +/*static void pack_vrt_header( + size_t num_data_words, //input + const uhd::metadata_t &metadata, //input + uint32_t *vrt_header, //output + size_t &vrt_header_words //output +){ + // +} + +static void unpack_vrt_header( + size_t &num_data_words, //output + uhd::metadata_t &metadata, //output + const uint32_t *vrt_header, //input + size_t &vrt_header_words //output +){ + // +}*/ + +static inline void host_floats_to_usrp2_shorts( + int16_t *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)); + } +} + +static inline void usrp2_shorts_to_host_floats( + float *host_floats, + const int16_t *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); + } +} + +static inline void host_shorts_to_usrp2_shorts( + int16_t *usrp2_shorts, + const int16_t *host_shorts, + size_t num_samps +){ + for(size_t i = 0; i < num_samps; i++){ + usrp2_shorts[i] = htons(host_shorts[i]); + } +} + +static inline void usrp2_shorts_to_host_shorts( + int16_t *host_shorts, + const int16_t *usrp2_shorts, + size_t num_samps +){ + for(size_t i = 0; i < num_samps; i++){ + host_shorts[i] = ntohs(usrp2_shorts[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[max_vrt_header_words]; + 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 | + ((_stream_id_to_packet_seq[metadata.stream_id]++ << 16) & 0xf) | + ((boost::asio::buffer_size(buff)/sizeof(uint32_t)) & 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[1] = buff; + + //send and return number of samples + return (_data_transport->send(buffs) - vrt_hdr_size)/sizeof(sc16_t); +} + +/*********************************************************************** + * Receive Raw Data + **********************************************************************/ +size_t usrp2_impl::recv_raw( + const boost::asio::mutable_buffer &buff, + uhd::metadata_t &metadata +){ + //load the buffer vector + std::vector buffs(2); + uint32_t vrt_hdr[max_vrt_header_words]; + buffs[0] = boost::asio::buffer(vrt_hdr, max_vrt_header_words); + buffs[1] = buff; + + //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; + + //unpack the vrt header + 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]); + + //return the number of samples received + size_t num_words = vrt_header & 0xffff; + return (num_words*sizeof(uint32_t))/sizeof(sc16_t); +} + +/*********************************************************************** + * Send Data + **********************************************************************/ +size_t usrp2_impl::send( + const boost::asio::const_buffer &buff, + const uhd::metadata_t &metadata, + const std::string &type +){ + if (type == "fc32"){ + 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)); + + host_floats_to_usrp2_shorts( + boost::asio::buffer_cast(raw_buff), + boost::asio::buffer_cast(buff), + num_samps*2 //double for complex + ); + + return send_raw(raw_buff, metadata); + } + + if (type == "sc16"){ + #ifdef HAVE_BIG_ENDIAN + return send_raw(buff, metadata); + #else + size_t num_samps = boost::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), + num_samps*2 //double for complex + ); + + return send_raw(raw_buff, metadata); + #endif + } + + throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%s\"") % type)); +} + +/*********************************************************************** + * Receive Data + **********************************************************************/ +size_t usrp2_impl::recv( + const boost::asio::mutable_buffer &buff, + uhd::metadata_t &metadata, + const std::string &type +){ + if (type == "fc32"){ + 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)); + + num_samps = recv_raw(raw_buff, metadata); + + usrp2_shorts_to_host_floats( + boost::asio::buffer_cast(buff), + boost::asio::buffer_cast(raw_buff), + num_samps*2 //double for complex + ); + + return num_samps; + } + + if (type == "sc16"){ + #ifdef HAVE_BIG_ENDIAN + return recv_raw(buff, metadata); + #else + size_t num_samps = boost::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), + num_samps*2 //double for complex + ); + + return num_samps; + #endif + } + + throw std::runtime_error(str(boost::format("usrp2 recv: cannot handle type \"%s\"") % type)); +} diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 47bf06aff..11e2f480b 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -44,19 +44,21 @@ uhd::device_addrs_t usrp2::discover(const device_addr_t &hint){ //loop and recieve until the time is up size_t num_timeouts = 0; while(true){ - uhd::shared_iovec iov = udp_transport->recv(); - //std::cout << boost::asio::buffer_size(buff) << "\n"; - if (iov.len < sizeof(usrp2_ctrl_data_t)){ + usrp2_ctrl_data_t ctrl_data_in; + size_t len = udp_transport->recv( + boost::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{ //handle the received data - const usrp2_ctrl_data_t *ctrl_data_in = reinterpret_cast(iov.base); - switch(ntohl(ctrl_data_in->id)){ + switch(ntohl(ctrl_data_in.id)){ case USRP2_CTRL_ID_THIS_IS_MY_IP_ADDR_DUDE: //make a boost asio ipv4 with the raw addr in host byte order - boost::asio::ip::address_v4 ip_addr(ntohl(ctrl_data_in->data.ip_addr)); + 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"] = "udp"; @@ -161,14 +163,16 @@ usrp2_ctrl_data_t usrp2_impl::ctrl_send_and_recv(const usrp2_ctrl_data_t &out_da //loop and recieve until the time is up size_t num_timeouts = 0; while(true){ - uhd::shared_iovec iov = _ctrl_transport->recv(); - if (iov.len < sizeof(usrp2_ctrl_data_t)){ + 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 - usrp2_ctrl_data_t in_data = *reinterpret_cast(iov.base); if (ntohl(in_data.seq) == _ctrl_seq_num){ return in_data; } @@ -204,76 +208,3 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){ void usrp2_impl::set(const wax::obj &, const wax::obj &){ throw std::runtime_error("Cannot set in usrp2 device"); } - -/*********************************************************************** - * IO Interface - **********************************************************************/ -static const float float_scale_factor = pow(2.0, 15); - -size_t usrp2_impl::send( - const boost::asio::const_buffer &buff, - const uhd::metadata_t &metadata, - const std::string &type -){ - if (type == "fc32"){ - //extract the buffer elements - const float *float_buff = boost::asio::buffer_cast(buff); - const size_t buff_len = boost::asio::buffer_size(buff)/sizeof(float); - - //convert floats into the shorts buffer - int16_t *shorts_buff = new int16_t[buff_len]; - for (size_t i = 0; i < buff_len; i++){ - shorts_buff[i] = float_buff[i]*float_scale_factor; - } - - //send from a buffer of shorts - size_t bytes_sent = send( - boost::asio::buffer(shorts_buff, buff_len*sizeof(int16_t)), - metadata, "sc16" - ); - - //cleanup - delete [] shorts_buff; - return bytes_sent; - } - - if (type == "sc16"){ - throw std::runtime_error("not implemented"); - } - - throw std::runtime_error(str(boost::format("usrp2 send: cannot handle type \"%s\"") % type)); -} - -size_t usrp2_impl::recv( - const boost::asio::mutable_buffer &buff, - uhd::metadata_t &metadata, - const std::string &type -){ - if (type == "fc32"){ - //extract the buffer elements - float *float_buff = boost::asio::buffer_cast(buff); - const size_t buff_len = boost::asio::buffer_size(buff)/sizeof(float); - - //receive into a buffer of shorts - int16_t *shorts_buff = new int16_t[buff_len]; - size_t bytes_received = recv( - boost::asio::buffer(shorts_buff, buff_len*sizeof(int16_t)), - metadata, "sc16" - ); - - //convert floats into the shorts buffer - for (size_t i = 0; i < bytes_received/sizeof(int16_t); i++){ - float_buff[i] = shorts_buff[i]/float_scale_factor; - } - - //cleanup - delete [] shorts_buff; - return bytes_received; - } - - if (type == "sc16"){ - throw std::runtime_error("not implemented"); - } - - throw std::runtime_error(str(boost::format("usrp2 recv: cannot handle type \"%s\"") % type)); -} diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 2476bcf1d..9a4c42d42 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -102,6 +102,11 @@ public: size_t recv(const boost::asio::mutable_buffer &, uhd::metadata_t &, const std::string &); 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; + //udp transports for control and data uhd::transport::udp::sptr _ctrl_transport; uhd::transport::udp::sptr _data_transport; -- cgit v1.2.3 From a9f8ba6e37e1349ce61b5022ddaff1c64dd52bd3 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 25 Feb 2010 18:26:00 +0000 Subject: added usrp1e conditional compilation, and checking of device node (aka file for now) --- host/lib/CMakeLists.txt | 14 ++++++-- host/lib/usrp/usrp1e/usrp1e_impl.cpp | 69 ++++++++++++++++++++++++++++++++++++ host/lib/usrp/usrp1e/usrp1e_impl.hpp | 23 ++++++++++++ host/lib/usrp/usrp2/usrp2_impl.cpp | 1 - 4 files changed, 103 insertions(+), 4 deletions(-) create mode 100644 host/lib/usrp/usrp1e/usrp1e_impl.cpp create mode 100644 host/lib/usrp/usrp1e/usrp1e_impl.hpp (limited to 'host/lib/usrp/usrp2/usrp2_impl.cpp') diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index edfefa127..96fba6e53 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -41,9 +41,17 @@ SET(libuhd_sources ######################################################################## # Conditionally add the usrp1e sources ######################################################################## -LIST(APPEND libuhd_sources - usrp/usrp1e/usrp1e_none.cpp -) +INCLUDE(CheckIncludeFile) +CHECK_INCLUDE_FILE("linux/ioctl.h" HAS_LINUX_IOCTL_H) +IF(HAS_LINUX_IOCTL_H) + LIST(APPEND libuhd_sources + usrp/usrp1e/usrp1e_impl.cpp + ) +ELSE(HAS_LINUX_IOCTL_H) + LIST(APPEND libuhd_sources + usrp/usrp1e/usrp1e_none.cpp + ) +ENDIF(HAS_LINUX_IOCTL_H) ######################################################################## # Setup libuhd library diff --git a/host/lib/usrp/usrp1e/usrp1e_impl.cpp b/host/lib/usrp/usrp1e/usrp1e_impl.cpp new file mode 100644 index 000000000..93265ab17 --- /dev/null +++ b/host/lib/usrp/usrp1e/usrp1e_impl.cpp @@ -0,0 +1,69 @@ +// +// 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 "usrp1e_impl.hpp" + +using namespace uhd; +using namespace uhd::usrp; + +/*********************************************************************** + * Helper Functions + **********************************************************************/ +static bool file_exists(const std::string &file_path){ + return access(file_path.c_str(), F_OK) == 0; +} + +/*********************************************************************** + * Discovery + **********************************************************************/ +device_addrs_t usrp1e::discover(const device_addr_t &device_addr){ + device_addrs_t usrp1e_addrs; + + //if a node was provided, use it and only it + if (device_addr.has_key("node")){ + if (not file_exists(device_addr["node"])) return usrp1e_addrs; + device_addr_t new_addr; + new_addr["name"] = "USRP1E"; + new_addr["type"] = "usrp1e"; + new_addr["node"] = device_addr["node"]; + usrp1e_addrs.push_back(new_addr); + } + + //otherwise look for a few nodes at small indexes + else{ + for(size_t i = 0; i < 5; i++){ + std::string node = str(boost::format("/dev/usrp1_e%d") % i); + if (not file_exists(node)) continue; + device_addr_t new_addr; + new_addr["name"] = "USRP1E"; + new_addr["type"] = "usrp1e"; + new_addr["node"] = node; + usrp1e_addrs.push_back(new_addr); + } + } + + return usrp1e_addrs; +} + +/*********************************************************************** + * Make + **********************************************************************/ +device::sptr usrp1e::make(const device_addr_t &){ + throw std::runtime_error("not implemented yet"); +} diff --git a/host/lib/usrp/usrp1e/usrp1e_impl.hpp b/host/lib/usrp/usrp1e/usrp1e_impl.hpp new file mode 100644 index 000000000..3f5f89ec6 --- /dev/null +++ b/host/lib/usrp/usrp1e/usrp1e_impl.hpp @@ -0,0 +1,23 @@ +// +// 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 + +#ifndef INCLUDED_USRP1E_IMPL_HPP +#define INCLUDED_USRP1E_IMPL_HPP + +#endif /* INCLUDED_USRP1E_IMPL_HPP */ diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 06876d241..5aa5d6e8d 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -62,7 +62,6 @@ uhd::device_addrs_t usrp2::discover(const device_addr_t &hint){ 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); break; -- cgit v1.2.3 From 3571f65a1184dd65be39bc19708cc316fd017497 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 25 Feb 2010 12:48:51 -0800 Subject: use a single addr param for the usrp2 --- host/apps/discover_usrps.cpp | 14 ++++++-------- host/lib/device.cpp | 7 ++----- host/lib/usrp/usrp2/usrp2_impl.cpp | 4 ++-- 3 files changed, 10 insertions(+), 15 deletions(-) (limited to 'host/lib/usrp/usrp2/usrp2_impl.cpp') diff --git a/host/apps/discover_usrps.cpp b/host/apps/discover_usrps.cpp index 02c05b7cc..08135a27c 100644 --- a/host/apps/discover_usrps.cpp +++ b/host/apps/discover_usrps.cpp @@ -22,13 +22,12 @@ #include namespace po = boost::program_options; -using namespace uhd; int main(int argc, char *argv[]){ po::options_description desc("Allowed options"); desc.add_options() ("help", "help message") - ("ip-addr", po::value(), "usrp2 ip address") + ("addr", po::value(), "resolvable network address") ; po::variables_map vm; @@ -41,13 +40,12 @@ int main(int argc, char *argv[]){ return ~0; } - //extract the ip address (not optional for now) + //extract the address (not optional for now) uhd::device_addr_t device_addr; - device_addr["type"] = "udp"; - if (vm.count("ip-addr")) { - device_addr["addr"] = vm["ip-addr"].as(); + if (vm.count("addr")) { + device_addr["addr"] = vm["addr"].as(); } else { - std::cout << "IP Addess was not set" << std::endl; + std::cout << "The address was not set" << std::endl; return ~0; } @@ -59,7 +57,7 @@ int main(int argc, char *argv[]){ 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 = device::make(device_addrs[i]); + 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; } diff --git a/host/lib/device.cpp b/host/lib/device.cpp index e376a5c50..f181d31e4 100644 --- a/host/lib/device.cpp +++ b/host/lib/device.cpp @@ -24,10 +24,7 @@ using namespace uhd; device_addrs_t device::discover(const device_addr_t &hint){ device_addrs_t device_addrs; - if (not hint.has_key("type")){ - //TODO call discover for others and append results - } - else if (hint["type"] == "udp"){ + 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()); } @@ -53,7 +50,7 @@ device::sptr device::make(const device_addr_t &hint, size_t which){ //create the new device with the discovered address //TODO only a usrp2 device will be made (until others are supported) - if (hint.has_key("type") and hint["type"] == "udp"){ + if (hint.has_key("addr")){ return usrp::usrp2::make(device_addrs.at(which)); } throw std::runtime_error("cant make a device"); diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 11e2f480b..770fa3e53 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -60,8 +60,8 @@ uhd::device_addrs_t usrp2::discover(const device_addr_t &hint){ //make a boost asio ipv4 with the raw addr in host byte order boost::asio::ip::address_v4 ip_addr(ntohl(ctrl_data_in.data.ip_addr)); device_addr_t new_addr; - new_addr["name"] = "USRP2"; - new_addr["type"] = "udp"; + new_addr["name"] = "usrp2"; + new_addr["transport"] = "udp"; new_addr["addr"] = ip_addr.to_string(); usrp2_addrs.push_back(new_addr); break; -- cgit v1.2.3 From 5715b2c4937ca094ca8f1d9d9b55c4edcc959981 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Thu, 25 Feb 2010 18:32:32 -0800 Subject: Created empty usrp1e cpp file for the case when headers are not found. Worked on the device make and discovery to fix certain problems. Added node param to discover usrps for usrp1e, made addr optional. --- host/apps/discover_usrps.cpp | 21 +++++--- host/include/uhd/device.hpp | 4 -- host/include/uhd/device_addr.hpp | 4 +- host/include/uhd/usrp/CMakeLists.txt | 1 + host/include/uhd/usrp/usrp1e.hpp | 48 +++++++++++++++++ host/include/uhd/usrp/usrp2.hpp | 6 +-- host/lib/CMakeLists.txt | 14 ++++- host/lib/device.cpp | 100 +++++++++++++++++++++++++++++------ host/lib/device_addr.cpp | 4 +- host/lib/usrp/usrp1e/usrp1e_none.cpp | 34 ++++++++++++ host/lib/usrp/usrp2/usrp2_impl.cpp | 3 +- 11 files changed, 204 insertions(+), 35 deletions(-) create mode 100644 host/include/uhd/usrp/usrp1e.hpp create mode 100644 host/lib/usrp/usrp1e/usrp1e_none.cpp (limited to 'host/lib/usrp/usrp2/usrp2_impl.cpp') diff --git a/host/apps/discover_usrps.cpp b/host/apps/discover_usrps.cpp index 08135a27c..7e8c21673 100644 --- a/host/apps/discover_usrps.cpp +++ b/host/apps/discover_usrps.cpp @@ -28,6 +28,7 @@ int main(int argc, char *argv[]){ desc.add_options() ("help", "help message") ("addr", po::value(), "resolvable network address") + ("node", po::value(), "path to linux device node") ; po::variables_map vm; @@ -35,22 +36,28 @@ int main(int argc, char *argv[]){ po::notify(vm); //print the help message - if (vm.count("help")) { + if (vm.count("help")){ std::cout << boost::format("Discover USRPs %s") % desc << std::endl; return ~0; } - //extract the address (not optional for now) + //load the options into the address uhd::device_addr_t device_addr; - if (vm.count("addr")) { + if (vm.count("addr")){ device_addr["addr"] = vm["addr"].as(); - } else { - std::cout << "The address was not set" << std::endl; + } + if (vm.count("node")){ + device_addr["node"] = vm["node"].as(); + } + + //discover the usrps and print the results + uhd::device_addrs_t device_addrs = uhd::device::discover(device_addr); + + if (device_addrs.size() == 0){ + std::cerr << "No USRP Devices Found" << std::endl; return ~0; } - //discover the usrps - std::vector device_addrs = uhd::device::discover(device_addr); for (size_t i = 0; i < device_addrs.size(); i++){ std::cout << "--------------------------------------------------" << std::endl; std::cout << "-- USRP Device " << i << std::endl; diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index 596a98bc4..ba5337d33 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -38,10 +38,6 @@ class device : boost::noncopyable, public wax::obj{ public: typedef boost::shared_ptr sptr; - //structors - device(void); - virtual ~device(void); - /*! * \brief Discover usrp devices attached to the host. * diff --git a/host/include/uhd/device_addr.hpp b/host/include/uhd/device_addr.hpp index 8ea580321..d02febd6c 100644 --- a/host/include/uhd/device_addr.hpp +++ b/host/include/uhd/device_addr.hpp @@ -56,7 +56,9 @@ namespace uhd{ * \param device_addr a device address instance * \return the string representation */ - std::string device_addr_to_string(const device_addr_t &device_addr); + struct device_addr{ + static std::string to_string(const device_addr_t &device_addr); + }; } //namespace uhd diff --git a/host/include/uhd/usrp/CMakeLists.txt b/host/include/uhd/usrp/CMakeLists.txt index e7bdc1784..4e0a92365 100644 --- a/host/include/uhd/usrp/CMakeLists.txt +++ b/host/include/uhd/usrp/CMakeLists.txt @@ -21,6 +21,7 @@ INSTALL(FILES dboard_id.hpp dboard_interface.hpp dboard_manager.hpp + usrp1e.hpp usrp2.hpp DESTINATION ${HEADER_DIR}/uhd/usrp ) diff --git a/host/include/uhd/usrp/usrp1e.hpp b/host/include/uhd/usrp/usrp1e.hpp new file mode 100644 index 000000000..00748e55f --- /dev/null +++ b/host/include/uhd/usrp/usrp1e.hpp @@ -0,0 +1,48 @@ +// +// 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_USRP_USRP1E_HPP +#define INCLUDED_UHD_USRP_USRP1E_HPP + +#include + +namespace uhd{ namespace usrp{ + +/*! + * The usrp1e device class. + */ +class usrp1e : public device{ +public: + /*! + * Discover usrp1e devices on the system via the device node. + * This static method will be called by the device::discover. + * \param hint a device addr with the usrp1e address filled in + * \return a vector of device addresses for all usrp1es found + */ + static device_addrs_t discover(const device_addr_t &hint); + + /*! + * Make a usrp1e from a device address. + * \param addr the device address + * \return a device sptr to a new usrp1e + */ + static device::sptr make(const device_addr_t &addr); +}; + +}} //namespace + +#endif /* INCLUDED_UHD_USRP_USRP1E_HPP */ diff --git a/host/include/uhd/usrp/usrp2.hpp b/host/include/uhd/usrp/usrp2.hpp index f6e49cbd6..da7ec595a 100644 --- a/host/include/uhd/usrp/usrp2.hpp +++ b/host/include/uhd/usrp/usrp2.hpp @@ -15,8 +15,8 @@ // along with this program. If not, see . // -#ifndef INCLUDED_UHD_USRP_MBOARD_USRP2_HPP -#define INCLUDED_UHD_USRP_MBOARD_USRP2_HPP +#ifndef INCLUDED_UHD_USRP_USRP2_HPP +#define INCLUDED_UHD_USRP_USRP2_HPP #include @@ -45,4 +45,4 @@ public: }} //namespace -#endif /* INCLUDED_UHD_USRP_MBOARD_USRP2_HPP */ +#endif /* INCLUDED_UHD_USRP_USRP2_HPP */ diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index 253f45614..edfefa127 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -15,7 +15,9 @@ # along with this program. If not, see . # - +######################################################################## +# Create a list of libuhd sources +######################################################################## SET(libuhd_sources device.cpp device_addr.cpp @@ -36,6 +38,16 @@ SET(libuhd_sources usrp/usrp2/usrp2_impl.cpp ) +######################################################################## +# Conditionally add the usrp1e sources +######################################################################## +LIST(APPEND libuhd_sources + usrp/usrp1e/usrp1e_none.cpp +) + +######################################################################## +# Setup libuhd library +######################################################################## ADD_LIBRARY(uhd SHARED ${libuhd_sources}) TARGET_LINK_LIBRARIES(uhd ${Boost_LIBRARIES}) diff --git a/host/lib/device.cpp b/host/lib/device.cpp index f181d31e4..82052708a 100644 --- a/host/lib/device.cpp +++ b/host/lib/device.cpp @@ -12,54 +12,122 @@ // 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 . +// asize_t with this program. If not, see . // +#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 + * \return a smart pointer to a device + */ +static device::sptr make_device(const device_addr_t &dev_addr){ + + //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("cant make a device"); +} + +/*! + * Make a device hash that maps 1 to 1 with a device address. + * The hash will be used to identify created devices. + * \param dev_addr the device address + * \return the hash number + */ +static size_t hash_device_addr( + const device_addr_t &dev_addr +){ + //sort the keys of the device address + std::vector keys = dev_addr.get_keys(); + std::sort(keys.begin(), keys.end()); + + //combine the hashes of sorted keys/value pairs + size_t hash = 0; + BOOST_FOREACH(std::string key, keys){ + boost::hash_combine(hash, key); + boost::hash_combine(hash, dev_addr[key]); + } + return hash; +} + +/*********************************************************************** + * 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()); } + return device_addrs; } +/*********************************************************************** + * Make + **********************************************************************/ device::sptr device::make(const device_addr_t &hint, size_t which){ std::vector device_addrs = discover(hint); //check that we found any devices if (device_addrs.size() == 0){ throw std::runtime_error(str( - boost::format("No devices found for %s") % device_addr_to_string(hint) + boost::format("No devices found for %s") % device_addr::to_string(hint) )); } //check that the which index is valid if (device_addrs.size() <= which){ throw std::runtime_error(str( - boost::format("No device at index %d for %s") % which % device_addr_to_string(hint) + boost::format("No device at index %d for %s") % which % device_addr::to_string(hint) )); } - //create the new device with the discovered address - //TODO only a usrp2 device will be made (until others are supported) - if (hint.has_key("addr")){ - return usrp::usrp2::make(device_addrs.at(which)); - } - throw std::runtime_error("cant make a device"); -} + //create a unique hash for the device address + device_addr_t dev_addr = device_addrs.at(which); + size_t dev_hash = hash_device_addr(dev_addr); + //std::cout << boost::format("Hash: %u") % dev_hash << std::endl; -device::device(void){ - /* NOP */ -} + //map device address hash to created devices + static uhd::dict > hash_to_device; -device::~device(void){ - /* NOP */ + //try to find an existing device + try{ + ASSERT_THROW(hash_to_device.has_key(dev_hash)); + ASSERT_THROW(not hash_to_device[dev_hash].expired()); + return hash_to_device[dev_hash].lock(); + } + //create and register a new device + catch(const std::assert_error &e){ + device::sptr dev = make_device(dev_addr); + hash_to_device[dev_hash] = dev; + return dev; + } } diff --git a/host/lib/device_addr.cpp b/host/lib/device_addr.cpp index ffd511f92..9514df981 100644 --- a/host/lib/device_addr.cpp +++ b/host/lib/device_addr.cpp @@ -72,7 +72,7 @@ std::ostream& operator<<(std::ostream &os, const uhd::mac_addr_t &x){ } //----------------------- usrp device_addr_t wrapper -------------------------// -std::string uhd::device_addr_to_string(const uhd::device_addr_t &device_addr){ +std::string uhd::device_addr::to_string(const uhd::device_addr_t &device_addr){ std::stringstream ss; BOOST_FOREACH(std::string key, device_addr.get_keys()){ ss << boost::format("%s: %s") % key % device_addr[key] << std::endl; @@ -81,6 +81,6 @@ std::string uhd::device_addr_to_string(const uhd::device_addr_t &device_addr){ } std::ostream& operator<<(std::ostream &os, const uhd::device_addr_t &device_addr){ - os << uhd::device_addr_to_string(device_addr); + os << uhd::device_addr::to_string(device_addr); return os; } diff --git a/host/lib/usrp/usrp1e/usrp1e_none.cpp b/host/lib/usrp/usrp1e/usrp1e_none.cpp new file mode 100644 index 000000000..1c8cf9a5b --- /dev/null +++ b/host/lib/usrp/usrp1e/usrp1e_none.cpp @@ -0,0 +1,34 @@ +// +// 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; +using namespace uhd::usrp; + +/*! + * This file defines the usrp1e discover and make functions + * when the required kernel module headers are not present. + */ + +device_addrs_t usrp1e::discover(const device_addr_t &){ + return device_addrs_t(); //return empty list +} + +device::sptr usrp1e::make(const device_addr_t &){ + throw std::runtime_error("this build has no usrp1e support"); +} diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 770fa3e53..06876d241 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -60,7 +60,8 @@ uhd::device_addrs_t usrp2::discover(const device_addr_t &hint){ //make a boost asio ipv4 with the raw addr in host byte order boost::asio::ip::address_v4 ip_addr(ntohl(ctrl_data_in.data.ip_addr)); device_addr_t new_addr; - new_addr["name"] = "usrp2"; + 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 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(-) (limited to 'host/lib/usrp/usrp2/usrp2_impl.cpp') 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 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 (limited to 'host/lib/usrp/usrp2/usrp2_impl.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 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(-) (limited to 'host/lib/usrp/usrp2/usrp2_impl.cpp') 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 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(-) (limited to 'host/lib/usrp/usrp2/usrp2_impl.cpp') 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 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(-) (limited to 'host/lib/usrp/usrp2/usrp2_impl.cpp') 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 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(-) (limited to 'host/lib/usrp/usrp2/usrp2_impl.cpp') 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 From 26ada5ee709fc4d7e195d19720b467c14368bc05 Mon Sep 17 00:00:00 2001 From: Josh Blum Date: Fri, 19 Mar 2010 18:08:20 -0800 Subject: added install path for dll, fixed idiotic msvc error where making a vector with proxies crashes the app, seems to be ok with the sptr fix, in other good news, discover usrps works in my vm for the usrp2 --- host/lib/CMakeLists.txt | 5 +++-- host/lib/usrp/usrp2/dboard_impl.cpp | 4 ++-- host/lib/usrp/usrp2/dsp_impl.cpp | 4 ++-- host/lib/usrp/usrp2/mboard_impl.cpp | 10 ++++----- host/lib/usrp/usrp2/usrp2_impl.cpp | 2 +- host/lib/usrp/usrp2/usrp2_impl.hpp | 43 +++++++++++++++++++------------------ 6 files changed, 35 insertions(+), 33 deletions(-) (limited to 'host/lib/usrp/usrp2/usrp2_impl.cpp') diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index 8e6bd693c..875a065af 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -64,6 +64,7 @@ TARGET_LINK_LIBRARIES(uhd ${Boost_LIBRARIES}) SET_TARGET_PROPERTIES(uhd PROPERTIES DEFINE_SYMBOL "UHD_DLL_EXPORTS") INSTALL(TARGETS uhd - LIBRARY DESTINATION ${LIBRARY_DIR} - ARCHIVE DESTINATION ${LIBRARY_DIR} + LIBRARY DESTINATION ${LIBRARY_DIR} # .so file + ARCHIVE DESTINATION ${LIBRARY_DIR} # .lib file + RUNTIME DESTINATION ${LIBRARY_DIR} # .dll file ) diff --git a/host/lib/usrp/usrp2/dboard_impl.cpp b/host/lib/usrp/usrp2/dboard_impl.cpp index 60622ca47..66e02d469 100644 --- a/host/lib/usrp/usrp2/dboard_impl.cpp +++ b/host/lib/usrp/usrp2/dboard_impl.cpp @@ -45,11 +45,11 @@ void usrp2_impl::dboard_init(void){ ); //load dboards - _rx_dboards[""] = wax_obj_proxy( + _rx_dboards[""] = wax_obj_proxy::make( boost::bind(&usrp2_impl::rx_dboard_get, this, _1, _2), boost::bind(&usrp2_impl::rx_dboard_set, this, _1, _2) ); - _tx_dboards[""] = wax_obj_proxy( + _tx_dboards[""] = wax_obj_proxy::make( boost::bind(&usrp2_impl::tx_dboard_get, this, _1, _2), boost::bind(&usrp2_impl::tx_dboard_set, this, _1, _2) ); diff --git a/host/lib/usrp/usrp2/dsp_impl.cpp b/host/lib/usrp/usrp2/dsp_impl.cpp index 54ed45e41..34cce0afb 100644 --- a/host/lib/usrp/usrp2/dsp_impl.cpp +++ b/host/lib/usrp/usrp2/dsp_impl.cpp @@ -53,7 +53,7 @@ static boost::uint32_t calculate_iq_scale_word(boost::int16_t i, boost::int16_t void usrp2_impl::init_ddc_config(void){ //create the ddc in the rx dsp dict - _rx_dsps["ddc0"] = wax_obj_proxy( + _rx_dsps["ddc0"] = wax_obj_proxy::make( boost::bind(&usrp2_impl::ddc_get, this, _1, _2), boost::bind(&usrp2_impl::ddc_set, this, _1, _2) ); @@ -201,7 +201,7 @@ void usrp2_impl::ddc_set(const wax::obj &key, const wax::obj &val){ **********************************************************************/ void usrp2_impl::init_duc_config(void){ //create the duc in the tx dsp dict - _tx_dsps["duc0"] = wax_obj_proxy( + _tx_dsps["duc0"] = wax_obj_proxy::make( boost::bind(&usrp2_impl::duc_get, this, _1, _2), boost::bind(&usrp2_impl::duc_set, this, _1, _2) ); diff --git a/host/lib/usrp/usrp2/mboard_impl.cpp b/host/lib/usrp/usrp2/mboard_impl.cpp index 4b15c7f3e..4f63e6cc9 100644 --- a/host/lib/usrp/usrp2/mboard_impl.cpp +++ b/host/lib/usrp/usrp2/mboard_impl.cpp @@ -25,7 +25,7 @@ using namespace uhd; * Helper Methods **********************************************************************/ void usrp2_impl::mboard_init(void){ - _mboards[""] = wax_obj_proxy( + _mboards[""] = wax_obj_proxy::make( boost::bind(&usrp2_impl::mboard_get, this, _1, _2), boost::bind(&usrp2_impl::mboard_set, this, _1, _2) ); @@ -137,7 +137,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ case MBOARD_PROP_RX_DBOARD: ASSERT_THROW(_rx_dboards.has_key(name)); - val = _rx_dboards[name].get_link(); + val = _rx_dboards[name]->get_link(); return; case MBOARD_PROP_RX_DBOARD_NAMES: @@ -146,7 +146,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ case MBOARD_PROP_TX_DBOARD: ASSERT_THROW(_tx_dboards.has_key(name)); - val = _tx_dboards[name].get_link(); + val = _tx_dboards[name]->get_link(); return; case MBOARD_PROP_TX_DBOARD_NAMES: @@ -159,7 +159,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ case MBOARD_PROP_RX_DSP: ASSERT_THROW(_rx_dsps.has_key(name)); - val = _rx_dsps[name].get_link(); + val = _rx_dsps[name]->get_link(); return; case MBOARD_PROP_RX_DSP_NAMES: @@ -168,7 +168,7 @@ void usrp2_impl::mboard_get(const wax::obj &key_, wax::obj &val){ case MBOARD_PROP_TX_DSP: ASSERT_THROW(_tx_dsps.has_key(name)); - val = _tx_dsps[name].get_link(); + val = _tx_dsps[name]->get_link(); return; case MBOARD_PROP_TX_DSP_NAMES: diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 22b7e109f..bdf8cc55b 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -191,7 +191,7 @@ void usrp2_impl::get(const wax::obj &key_, wax::obj &val){ case DEVICE_PROP_MBOARD: ASSERT_THROW(_mboards.has_key(name)); - val = _mboards[name].get_link(); + val = _mboards[name]->get_link(); return; case DEVICE_PROP_MBOARD_NAMES: diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 765c523fe..59e23aba5 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -15,6 +15,9 @@ // along with this program. If not, see . // +#ifndef INCLUDED_USRP2_IMPL_HPP +#define INCLUDED_USRP2_IMPL_HPP + #include #include #include @@ -28,9 +31,6 @@ #include #include "fw_common.h" -#ifndef INCLUDED_USRP2_IMPL_HPP -#define INCLUDED_USRP2_IMPL_HPP - class usrp2_impl; //dummy class declaration /*! @@ -50,20 +50,25 @@ class wax_obj_proxy : public wax::obj{ public: typedef boost::function get_t; typedef boost::function set_t; + typedef boost::shared_ptr sptr; + + static sptr make(const get_t &get, const set_t &set){ + return sptr(new wax_obj_proxy(get, set)); + } - wax_obj_proxy(void){ + ~wax_obj_proxy(void){ /* NOP */ } +private: + get_t _get; + set_t _set; + wax_obj_proxy(const get_t &get, const set_t &set){ _get = get; _set = set; }; - ~wax_obj_proxy(void){ - /* NOP */ - } - void get(const wax::obj &key, wax::obj &val){ return _get(key, val); } @@ -71,10 +76,6 @@ public: void set(const wax::obj &key, const wax::obj &val){ return _set(key, val); } - -private: - get_t _get; - set_t _set; }; /*! @@ -98,10 +99,6 @@ public: ~usrp2_impl(void); - //properties interface - void get(const wax::obj &, wax::obj &); - void set(const wax::obj &, const wax::obj &); - //performs a control transaction usrp2_ctrl_data_t ctrl_send_and_recv(const usrp2_ctrl_data_t &); @@ -113,6 +110,10 @@ public: size_t recv(const boost::asio::mutable_buffer &, uhd::rx_metadata_t &, const std::string &); private: + //device properties interface + void get(const wax::obj &, wax::obj &); + void set(const wax::obj &, const wax::obj &); + //the raw io interface (samples are in the usrp2 native format) void recv_raw(uhd::rx_metadata_t &); uhd::dict _tx_stream_id_to_packet_seq; @@ -159,18 +160,18 @@ private: void mboard_init(void); void mboard_get(const wax::obj &, wax::obj &); void mboard_set(const wax::obj &, const wax::obj &); - uhd::dict _mboards; + uhd::dict _mboards; //properties interface for rx dboard void rx_dboard_get(const wax::obj &, wax::obj &); void rx_dboard_set(const wax::obj &, const wax::obj &); - uhd::dict _rx_dboards; + uhd::dict _rx_dboards; uhd::prop_names_t _rx_subdevs_in_use; //properties interface for tx dboard void tx_dboard_get(const wax::obj &, wax::obj &); void tx_dboard_set(const wax::obj &, const wax::obj &); - uhd::dict _tx_dboards; + uhd::dict _tx_dboards; uhd::prop_names_t _tx_subdevs_in_use; void update_mux_config(void); @@ -193,12 +194,12 @@ private: //properties interface for ddc void ddc_get(const wax::obj &, wax::obj &); void ddc_set(const wax::obj &, const wax::obj &); - uhd::dict _rx_dsps; + uhd::dict _rx_dsps; //properties interface for duc void duc_get(const wax::obj &, wax::obj &); void duc_set(const wax::obj &, const wax::obj &); - uhd::dict _tx_dsps; + uhd::dict _tx_dsps; }; -- cgit v1.2.3