diff options
Diffstat (limited to 'host/include')
33 files changed, 1939 insertions, 329 deletions
diff --git a/host/include/linux/usrp_e.h b/host/include/linux/usrp_e.h index 80f3a287b..4c6a5dd89 100644 --- a/host/include/linux/usrp_e.h +++ b/host/include/linux/usrp_e.h @@ -65,12 +65,16 @@ struct usrp_e_i2c { #define USRP_E_I2C_READ _IOWR(USRP_E_IOC_MAGIC, 0x25, struct usrp_e_i2c) #define USRP_E_I2C_WRITE _IOW(USRP_E_IOC_MAGIC, 0x26, struct usrp_e_i2c) #define USRP_E_GET_RB_INFO _IOR(USRP_E_IOC_MAGIC, 0x27, struct usrp_e_ring_buffer_size_t) +#define USRP_E_GET_COMPAT_NUMBER _IO(USRP_E_IOC_MAGIC, 0x28) + +#define USRP_E_COMPAT_NUMBER 1 /* Flag defines */ #define RB_USER (1<<0) #define RB_KERNEL (1<<1) #define RB_OVERRUN (1<<2) #define RB_DMA_ACTIVE (1<<3) +#define RB_USER_PROCESS (1<<4) struct ring_buffer_info { int flags; diff --git a/host/include/uhd/config.hpp b/host/include/uhd/config.hpp index dacd3a96b..2918c2340 100644 --- a/host/include/uhd/config.hpp +++ b/host/include/uhd/config.hpp @@ -31,11 +31,12 @@ # pragma warning(disable: 4251) // class 'A<T>' needs to have dll-interface to be used by clients of class 'B' //# pragma warning(disable: 4127) // conditional expression is constant //# pragma warning(disable: 4290) // C++ exception specification ignored except to ... -# pragma warning(disable: 4180) // qualifier applied to function type has no meaning; ignored +//# pragma warning(disable: 4180) // qualifier applied to function type has no meaning; ignored # pragma warning(disable: 4275) // non dll-interface class ... used as base for dll-interface class ... //# pragma warning(disable: 4267) // 'var' : conversion from 'size_t' to 'type', possible loss of data //# pragma warning(disable: 4511) // 'class' : copy constructor could not be generated -# pragma warning(disable: 4250) // 'class' : inherits 'method' via dominance +//# pragma warning(disable: 4250) // 'class' : inherits 'method' via dominance +# pragma warning(disable: 4200) // nonstandard extension used : zero-sized array in struct/union #endif // define logical operators diff --git a/host/include/uhd/device.hpp b/host/include/uhd/device.hpp index 2077cae62..992276928 100644 --- a/host/include/uhd/device.hpp +++ b/host/include/uhd/device.hpp @@ -41,9 +41,6 @@ public: typedef boost::function<device_addrs_t(const device_addr_t &)> find_t; typedef boost::function<sptr(const device_addr_t &)> make_t; - //! A reasonable default timeout for receive - static const size_t default_recv_timeout_ms = 100; - /*! * Register a device into the discovery and factory system. * @@ -112,12 +109,15 @@ public: * * This is a blocking call and will not return until the number * of samples returned have been read out of each buffer. + * Under a timeout condition, the number of samples returned + * may be less than the number of samples specified. * * \param buffs a vector of read-only memory containing IF data * \param nsamps_per_buff the number of samples to send, per buffer * \param metadata data describing the buffer's contents * \param io_type the type of data loaded in the buffer * \param send_mode tells send how to unload the buffer + * \param timeout the timeout in seconds to wait on a packet * \return the number of samples sent */ virtual size_t send( @@ -125,7 +125,8 @@ public: size_t nsamps_per_buff, const tx_metadata_t &metadata, const io_type_t &io_type, - send_mode_t send_mode + send_mode_t send_mode, + double timeout = 0.1 ) = 0; /*! @@ -136,7 +137,8 @@ public: size_t nsamps_per_buff, const tx_metadata_t &metadata, const io_type_t &io_type, - send_mode_t send_mode + send_mode_t send_mode, + double timeout = 0.1 ); /*! @@ -154,7 +156,9 @@ public: * See the rx metadata fragment flags and offset fields for details. * * This is a blocking call and will not return until the number - * of samples returned have been written into each buffer or timeout. + * of samples returned have been written into each buffer. + * Under a timeout condition, the number of samples returned + * may be less than the number of samples specified. * * When using the full buffer recv mode, the metadata only applies * to the first packet received and written into the recv buffers. @@ -165,7 +169,7 @@ public: * \param metadata data to fill describing the buffer * \param io_type the type of data to fill into the buffer * \param recv_mode tells recv how to load the buffer - * \param timeout_ms the timeout in milliseconds to wait for a packet + * \param timeout the timeout in seconds to wait for a packet * \return the number of samples received or 0 on error */ virtual size_t recv( @@ -174,7 +178,7 @@ public: rx_metadata_t &metadata, const io_type_t &io_type, recv_mode_t recv_mode, - size_t timeout_ms = default_recv_timeout_ms + double timeout = 0.1 ) = 0; /*! @@ -186,7 +190,7 @@ public: rx_metadata_t &metadata, const io_type_t &io_type, recv_mode_t recv_mode, - size_t timeout_ms = default_recv_timeout_ms + double timeout = 0.1 ); /*! @@ -204,12 +208,11 @@ public: /*! * Receive and asynchronous message from the device. * \param async_metadata the metadata to be filled in - * \param timeout_ms the timeout in milliseconds to wait for a message + * \param timeout the timeout in seconds to wait for a message * \return true when the async_metadata is valid, false for timeout */ virtual bool recv_async_msg( - async_metadata_t &async_metadata, - size_t timeout_ms = default_recv_timeout_ms + async_metadata_t &async_metadata, double timeout = 0.1 ) = 0; }; diff --git a/host/include/uhd/device.ipp b/host/include/uhd/device.ipp index 60a3f535d..e2e51ecd0 100644 --- a/host/include/uhd/device.ipp +++ b/host/include/uhd/device.ipp @@ -25,12 +25,13 @@ namespace uhd{ size_t nsamps_per_buff, const tx_metadata_t &metadata, const io_type_t &io_type, - send_mode_t send_mode + send_mode_t send_mode, + double timeout ){ return this->send( std::vector<const void *>(1, buff), nsamps_per_buff, metadata, - io_type, send_mode + io_type, send_mode, timeout ); } @@ -40,12 +41,12 @@ namespace uhd{ rx_metadata_t &metadata, const io_type_t &io_type, recv_mode_t recv_mode, - size_t timeout_ms + double timeout ){ return this->recv( std::vector<void *>(1, buff), nsamps_per_buff, metadata, - io_type, recv_mode, timeout_ms + io_type, recv_mode, timeout ); } diff --git a/host/include/uhd/transport/alignment_buffer.hpp b/host/include/uhd/transport/alignment_buffer.hpp index 29ba74efc..f44a037f8 100644 --- a/host/include/uhd/transport/alignment_buffer.hpp +++ b/host/include/uhd/transport/alignment_buffer.hpp @@ -48,20 +48,17 @@ namespace uhd{ namespace transport{ * \return true if the element fit without popping for space */ virtual bool push_with_pop_on_full( - const elem_type &elem, - const seq_type &seq, - size_t index + const elem_type &elem, const seq_type &seq, size_t index ) = 0; /*! * Pop an aligned set of elements from this alignment buffer. * \param elems a collection to store the aligned elements - * \param time the timeout time + * \param timeout the timeout in seconds * \return false when the operation times out */ virtual bool pop_elems_with_timed_wait( - std::vector<elem_type> &elems, - const time_duration_t &time + std::vector<elem_type> &elems, double timeout ) = 0; }; diff --git a/host/include/uhd/transport/alignment_buffer.ipp b/host/include/uhd/transport/alignment_buffer.ipp index 61b3b60f5..833b5d399 100644 --- a/host/include/uhd/transport/alignment_buffer.ipp +++ b/host/include/uhd/transport/alignment_buffer.ipp @@ -41,9 +41,7 @@ namespace uhd{ namespace transport{ namespace{ /*anon*/ } UHD_INLINE bool push_with_pop_on_full( - const elem_type &elem, - const seq_type &seq, - size_t index + const elem_type &elem, const seq_type &seq, size_t index ){ //clear the buffer for this index if the seqs are mis-ordered if (seq < _last_seqs[index]){ @@ -54,17 +52,16 @@ namespace uhd{ namespace transport{ namespace{ /*anon*/ } UHD_INLINE bool pop_elems_with_timed_wait( - std::vector<elem_type> &elems, - const time_duration_t &time + std::vector<elem_type> &elems, double timeout ){ - boost::system_time exit_time = boost::get_system_time() + time; + boost::system_time exit_time = boost::get_system_time() + to_time_dur(timeout); buff_contents_type buff_contents_tmp; std::list<size_t> indexes_to_do(_all_indexes); //do an initial pop to load an initial sequence id size_t index = indexes_to_do.front(); if (not _buffs[index]->pop_with_timed_wait( - buff_contents_tmp, exit_time - boost::get_system_time() + buff_contents_tmp, from_time_dur(exit_time - boost::get_system_time()) )) return false; elems[index] = buff_contents_tmp.first; seq_type expected_seq_id = buff_contents_tmp.second; @@ -79,7 +76,7 @@ namespace uhd{ namespace transport{ namespace{ /*anon*/ indexes_to_do = _all_indexes; index = indexes_to_do.front(); if (not _buffs[index]->pop_with_timed_wait( - buff_contents_tmp, exit_time - boost::get_system_time() + buff_contents_tmp, from_time_dur(exit_time - boost::get_system_time()) )) return false; elems[index] = buff_contents_tmp.first; expected_seq_id = buff_contents_tmp.second; @@ -89,7 +86,7 @@ namespace uhd{ namespace transport{ namespace{ /*anon*/ //pop an element off for this index index = indexes_to_do.front(); if (not _buffs[index]->pop_with_timed_wait( - buff_contents_tmp, exit_time - boost::get_system_time() + buff_contents_tmp, from_time_dur(exit_time - boost::get_system_time()) )) return false; //if the sequence id matches: diff --git a/host/include/uhd/transport/bounded_buffer.hpp b/host/include/uhd/transport/bounded_buffer.hpp index d1deece96..aca93b071 100644 --- a/host/include/uhd/transport/bounded_buffer.hpp +++ b/host/include/uhd/transport/bounded_buffer.hpp @@ -20,13 +20,9 @@ #include <uhd/config.hpp> #include <boost/shared_ptr.hpp> -#include <boost/date_time/posix_time/posix_time_types.hpp> namespace uhd{ namespace transport{ - //! typedef for the time duration type for wait operations - typedef boost::posix_time::time_duration time_duration_t; - /*! * Implement a templated bounded buffer: * Used for passing elements between threads in a producer-consumer model. @@ -64,10 +60,10 @@ namespace uhd{ namespace transport{ * Push a new element into the bounded_buffer. * Wait until the bounded_buffer becomes non-full or timeout. * \param elem the new element to push - * \param time the timeout time + * \param timeout the timeout in seconds * \return false when the operation times out */ - virtual bool push_with_timed_wait(const elem_type &elem, const time_duration_t &time) = 0; + virtual bool push_with_timed_wait(const elem_type &elem, double timeout) = 0; /*! * Pop an element from the bounded_buffer. @@ -80,10 +76,10 @@ namespace uhd{ namespace transport{ * Pop an element from the bounded_buffer. * Wait until the bounded_buffer becomes non-empty or timeout. * \param elem the element reference pop to - * \param time the timeout time + * \param timeout the timeout in seconds * \return false when the operation times out */ - virtual bool pop_with_timed_wait(elem_type &elem, const time_duration_t &time) = 0; + virtual bool pop_with_timed_wait(elem_type &elem, double timeout) = 0; /*! * Clear all elements from the bounded_buffer. diff --git a/host/include/uhd/transport/bounded_buffer.ipp b/host/include/uhd/transport/bounded_buffer.ipp index e106e229e..edc7faa06 100644 --- a/host/include/uhd/transport/bounded_buffer.ipp +++ b/host/include/uhd/transport/bounded_buffer.ipp @@ -19,17 +19,28 @@ #define INCLUDED_UHD_TRANSPORT_BOUNDED_BUFFER_IPP #include <boost/bind.hpp> +#include <boost/function.hpp> #include <boost/circular_buffer.hpp> #include <boost/thread/condition.hpp> +#include <boost/date_time/posix_time/posix_time_types.hpp> namespace uhd{ namespace transport{ namespace{ /*anon*/ + static UHD_INLINE boost::posix_time::time_duration to_time_dur(double timeout){ + return boost::posix_time::microseconds(long(timeout*1e6)); + } + + static UHD_INLINE double from_time_dur(const boost::posix_time::time_duration &time_dur){ + return 1e-6*time_dur.total_microseconds(); + } + template <typename elem_type> class bounded_buffer_impl : public bounded_buffer<elem_type>{ public: bounded_buffer_impl(size_t capacity) : _buffer(capacity){ - /* NOP */ + _not_full_fcn = boost::bind(&bounded_buffer_impl<elem_type>::not_full, this); + _not_empty_fcn = boost::bind(&bounded_buffer_impl<elem_type>::not_empty, this); } UHD_INLINE bool push_with_pop_on_full(const elem_type &elem){ @@ -51,15 +62,17 @@ namespace uhd{ namespace transport{ namespace{ /*anon*/ UHD_INLINE void push_with_wait(const elem_type &elem){ boost::unique_lock<boost::mutex> lock(_mutex); - _full_cond.wait(lock, boost::bind(&bounded_buffer_impl<elem_type>::not_full, this)); + _full_cond.wait(lock, _not_full_fcn); _buffer.push_front(elem); lock.unlock(); _empty_cond.notify_one(); } - bool push_with_timed_wait(const elem_type &elem, const time_duration_t &time){ + UHD_INLINE bool push_with_timed_wait(const elem_type &elem, double timeout){ boost::unique_lock<boost::mutex> lock(_mutex); - if (not _full_cond.timed_wait(lock, time, boost::bind(&bounded_buffer_impl<elem_type>::not_full, this))) return false; + if (not _full_cond.timed_wait( + lock, to_time_dur(timeout), _not_full_fcn + )) return false; _buffer.push_front(elem); lock.unlock(); _empty_cond.notify_one(); @@ -68,16 +81,18 @@ namespace uhd{ namespace transport{ namespace{ /*anon*/ UHD_INLINE void pop_with_wait(elem_type &elem){ boost::unique_lock<boost::mutex> lock(_mutex); - _empty_cond.wait(lock, boost::bind(&bounded_buffer_impl<elem_type>::not_empty, this)); - elem = _buffer.back(); _buffer.pop_back(); + _empty_cond.wait(lock, _not_empty_fcn); + elem = this->pop_back(); lock.unlock(); _full_cond.notify_one(); } - bool pop_with_timed_wait(elem_type &elem, const time_duration_t &time){ + UHD_INLINE bool pop_with_timed_wait(elem_type &elem, double timeout){ boost::unique_lock<boost::mutex> lock(_mutex); - if (not _empty_cond.timed_wait(lock, time, boost::bind(&bounded_buffer_impl<elem_type>::not_empty, this))) return false; - elem = _buffer.back(); _buffer.pop_back(); + if (not _empty_cond.timed_wait( + lock, to_time_dur(timeout), _not_empty_fcn + )) return false; + elem = this->pop_back(); lock.unlock(); _full_cond.notify_one(); return true; @@ -85,7 +100,7 @@ namespace uhd{ namespace transport{ namespace{ /*anon*/ UHD_INLINE void clear(void){ boost::unique_lock<boost::mutex> lock(_mutex); - while (not_empty()) _buffer.pop_back(); + while (not_empty()) this->pop_back(); lock.unlock(); _full_cond.notify_one(); } @@ -97,6 +112,21 @@ namespace uhd{ namespace transport{ namespace{ /*anon*/ bool not_full(void) const{return not _buffer.full();} bool not_empty(void) const{return not _buffer.empty();} + + boost::function<bool(void)> _not_full_fcn, _not_empty_fcn; + + /*! + * Three part operation to pop an element: + * 1) assign elem to the back element + * 2) assign the back element to empty + * 3) pop the back to move the counter + */ + UHD_INLINE elem_type pop_back(void){ + elem_type elem = _buffer.back(); + _buffer.back() = elem_type(); + _buffer.pop_back(); + return elem; + } }; }}} //namespace diff --git a/host/include/uhd/transport/udp_zero_copy.hpp b/host/include/uhd/transport/udp_zero_copy.hpp index 818709973..bbba97b21 100644 --- a/host/include/uhd/transport/udp_zero_copy.hpp +++ b/host/include/uhd/transport/udp_zero_copy.hpp @@ -20,6 +20,7 @@ #include <uhd/config.hpp> #include <uhd/transport/zero_copy.hpp> +#include <uhd/types/device_addr.hpp> #include <boost/shared_ptr.hpp> namespace uhd{ namespace transport{ @@ -50,14 +51,12 @@ public: * * \param addr a string representing the destination address * \param port a string representing the destination port - * \param recv_buff_size size in bytes for the recv buffer, 0 for automatic - * \param send_buff_size size in bytes for the send buffer, 0 for automatic + * \param hints optional parameters to pass to the underlying transport */ static sptr make( const std::string &addr, const std::string &port, - size_t recv_buff_size = 0, - size_t send_buff_size = 0 + const device_addr_t &hints = device_addr_t() ); }; diff --git a/host/include/uhd/transport/usb_control.hpp b/host/include/uhd/transport/usb_control.hpp index 6137ecf84..e6c32f78e 100644 --- a/host/include/uhd/transport/usb_control.hpp +++ b/host/include/uhd/transport/usb_control.hpp @@ -18,7 +18,7 @@ #ifndef INCLUDED_UHD_TRANSPORT_USB_CONTROL_HPP #define INCLUDED_UHD_TRANSPORT_USB_CONTROL_HPP -#include "usb_device_handle.hpp" +#include <uhd/transport/usb_device_handle.hpp> namespace uhd { namespace transport { @@ -50,9 +50,9 @@ public: * \param index 2-byte (wIndex) * \param buff buffer to hold send or receive data * \param length 2-byte (wLength) - * \return number of bytes submitted + * \return number of bytes submitted or error code */ - virtual size_t submit(boost::uint8_t request_type, + virtual ssize_t submit(boost::uint8_t request_type, boost::uint8_t request, boost::uint16_t value, boost::uint16_t index, diff --git a/host/include/uhd/transport/usb_device_handle.hpp b/host/include/uhd/transport/usb_device_handle.hpp index 735a3acbe..6f8d868be 100644 --- a/host/include/uhd/transport/usb_device_handle.hpp +++ b/host/include/uhd/transport/usb_device_handle.hpp @@ -38,7 +38,7 @@ namespace uhd { namespace transport { * a true descriptor serial number string. This interface returns the * actual string descriptor. */ -class usb_device_handle : boost::noncopyable { +class UHD_API usb_device_handle : boost::noncopyable { public: typedef boost::shared_ptr<usb_device_handle> sptr; @@ -61,12 +61,6 @@ public: virtual boost::uint16_t get_product_id() const = 0; /*! - * Return the device's USB address - * \return a Product ID - */ - virtual boost::uint16_t get_device_addr() const = 0; - - /*! * Return a vector of USB devices on this host * \return a vector of USB device handles that match vid and pid */ diff --git a/host/include/uhd/transport/usb_zero_copy.hpp b/host/include/uhd/transport/usb_zero_copy.hpp index 75232c22a..b39171fba 100644 --- a/host/include/uhd/transport/usb_zero_copy.hpp +++ b/host/include/uhd/transport/usb_zero_copy.hpp @@ -18,8 +18,9 @@ #ifndef INCLUDED_UHD_TRANSPORT_USB_ZERO_COPY_HPP #define INCLUDED_UHD_TRANSPORT_USB_ZERO_COPY_HPP -#include "usb_device_handle.hpp" +#include <uhd/transport/usb_device_handle.hpp> #include <uhd/transport/zero_copy.hpp> +#include <uhd/types/device_addr.hpp> namespace uhd { namespace transport { @@ -45,16 +46,16 @@ public: * The underlying implementation may be platform specific. * * \param handle a device handle that uniquely identifying the device - * \param rx_endpoint an integer specifiying an IN endpoint number - * \param tx_endpoint an integer specifiying an OUT endpoint number - * \param buff_size total number of bytes of buffer space to allocate - * \param block_size number of bytes allocated for each I/O transaction + * \param recv_endpoint an integer specifiying an IN endpoint number + * \param send_endpoint an integer specifiying an OUT endpoint number + * \param hints optional parameters to pass to the underlying transport */ - static sptr make(usb_device_handle::sptr handle, - unsigned int rx_endpoint, - unsigned int tx_endpoint, - size_t buff_size = 0, - size_t block_size = 0); + static sptr make( + usb_device_handle::sptr handle, + size_t recv_endpoint, + size_t send_endpoint, + const device_addr_t &hints = device_addr_t() + ); }; }} //namespace diff --git a/host/include/uhd/transport/zero_copy.hpp b/host/include/uhd/transport/zero_copy.hpp index 513291b63..7d8fb4b83 100644 --- a/host/include/uhd/transport/zero_copy.hpp +++ b/host/include/uhd/transport/zero_copy.hpp @@ -19,10 +19,10 @@ #define INCLUDED_UHD_TRANSPORT_ZERO_COPY_HPP #include <uhd/config.hpp> -#include <uhd/utils/pimpl.hpp> #include <boost/asio/buffer.hpp> #include <boost/utility.hpp> #include <boost/shared_ptr.hpp> +#include <boost/function.hpp> namespace uhd{ namespace transport{ @@ -34,14 +34,27 @@ namespace uhd{ namespace transport{ class UHD_API managed_recv_buffer : boost::noncopyable{ public: typedef boost::shared_ptr<managed_recv_buffer> sptr; + typedef boost::function<void(void)> release_fcn_t; + + /*! + * Make a safe managed receive buffer: + * A safe managed buffer ensures that release is called once, + * either by the user or automatically upon deconstruction. + * \param buff a reference to the constant buffer + * \param release_fcn callback to release the memory + * \return a new managed receive buffer + */ + static sptr make_safe( + const boost::asio::const_buffer &buff, + const release_fcn_t &release_fcn + ); /*! - * Managed recv buffer destructor: * Signal to the transport that we are done with the buffer. - * This should be called to release the buffer to the transport. + * This should be called to release the buffer to the transport object. * After calling, the referenced memory should be considered invalid. */ - virtual ~managed_recv_buffer(void) = 0; + virtual void release(void) = 0; /*! * Get the size of the underlying buffer. @@ -71,20 +84,34 @@ namespace uhd{ namespace transport{ /*! * A managed send buffer: * Contains a reference to transport-managed memory, - * and a method to release the memory after writing. + * and a method to commit the memory after writing. */ class UHD_API managed_send_buffer : boost::noncopyable{ public: typedef boost::shared_ptr<managed_send_buffer> sptr; + typedef boost::function<void(size_t)> commit_fcn_t; + + /*! + * Make a safe managed send buffer: + * A safe managed buffer ensures that commit is called once, + * either by the user or automatically upon deconstruction. + * In the later case, the deconstructor will call commit(0). + * \param buff a reference to the mutable buffer + * \param commit_fcn callback to commit the memory + * \return a new managed send buffer + */ + static sptr make_safe( + const boost::asio::mutable_buffer &buff, + const commit_fcn_t &commit_fcn + ); /*! * Signal to the transport that we are done with the buffer. * This should be called to commit the write to the transport object. * After calling, the referenced memory should be considered invalid. * \param num_bytes the number of bytes written into the buffer - * \return the number of bytes written, 0 for timeout, negative for error */ - virtual ssize_t commit(size_t num_bytes) = 0; + virtual void commit(size_t num_bytes) = 0; /*! * Get the size of the underlying buffer. @@ -122,100 +149,46 @@ namespace uhd{ namespace transport{ /*! * Get a new receive buffer from this transport object. + * \param timeout the timeout to get the buffer in seconds * \return a managed buffer, or null sptr on timeout/error */ - virtual managed_recv_buffer::sptr get_recv_buff(void) = 0; + virtual managed_recv_buffer::sptr get_recv_buff(double timeout = 0.1) = 0; /*! - * Get the maximum number of receive frames: - * The maximum number of valid managed recv buffers, - * or the maximum number of frames in the ring buffer, - * depending upon the underlying implementation. + * Get the number of receive frames: + * The number of simultaneous receive buffers in use. * \return number of frames */ virtual size_t get_num_recv_frames(void) const = 0; /*! + * Get the size of a receive frame: + * The maximum capacity of a single receive buffer. + * \return frame size in bytes + */ + virtual size_t get_recv_frame_size(void) const = 0; + + /*! * Get a new send buffer from this transport object. + * \param timeout the timeout to get the buffer in seconds * \return a managed buffer, or null sptr on timeout/error */ - virtual managed_send_buffer::sptr get_send_buff(void) = 0; + virtual managed_send_buffer::sptr get_send_buff(double timeout = 0.1) = 0; /*! - * Get the maximum number of send frames: - * The maximum number of valid managed send buffers, - * or the maximum number of frames in the ring buffer, - * depending upon the underlying implementation. + * Get the number of send frames: + * The number of simultaneous send buffers in use. * \return number of frames */ virtual size_t get_num_send_frames(void) const = 0; - }; - - /*! - * A phony-zero-copy interface for transport objects that - * provides a zero-copy interface on top of copying transport. - * This interface implements the get managed recv buffer, - * the base class must implement the private recv method. - */ - class UHD_API phony_zero_copy_recv_if : public virtual zero_copy_if{ - public: - /*! - * Create a phony zero copy recv interface. - * \param max_buff_size max buffer size in bytes - */ - phony_zero_copy_recv_if(size_t max_buff_size); - - //! destructor - virtual ~phony_zero_copy_recv_if(void); - - /*! - * Get a new receive buffer from this transport object. - */ - managed_recv_buffer::sptr get_recv_buff(void); - - private: - /*! - * Perform a private copying recv. - * \param buff the buffer to write data into - * \return the number of bytes written to buff, 0 for timeout, negative for error - */ - virtual ssize_t recv(const boost::asio::mutable_buffer &buff) = 0; - - UHD_PIMPL_DECL(impl) _impl; - }; - - /*! - * A phony-zero-copy interface for transport objects that - * provides a zero-copy interface on top of copying transport. - * This interface implements the get managed send buffer, - * the base class must implement the private send method. - */ - class UHD_API phony_zero_copy_send_if : public virtual zero_copy_if{ - public: - /*! - * Create a phony zero copy send interface. - * \param max_buff_size max buffer size in bytes - */ - phony_zero_copy_send_if(size_t max_buff_size); - - //! destructor - virtual ~phony_zero_copy_send_if(void); - - /*! - * Get a new send buffer from this transport object. - */ - managed_send_buffer::sptr get_send_buff(void); - - private: /*! - * Perform a private copying send. - * \param buff the buffer to read data from - * \return the number of bytes read from buff, 0 for timeout, negative for error + * Get the size of a send frame: + * The maximum capacity of a single send buffer. + * \return frame size in bytes */ - virtual ssize_t send(const boost::asio::const_buffer &buff) = 0; + virtual size_t get_send_frame_size(void) const = 0; - UHD_PIMPL_DECL(impl) _impl; }; }} //namespace diff --git a/host/include/uhd/types/CMakeLists.txt b/host/include/uhd/types/CMakeLists.txt index dbce21c98..a96976b5e 100644 --- a/host/include/uhd/types/CMakeLists.txt +++ b/host/include/uhd/types/CMakeLists.txt @@ -19,6 +19,7 @@ INSTALL(FILES clock_config.hpp device_addr.hpp + dict.ipp dict.hpp io_type.hpp mac_addr.hpp @@ -28,6 +29,7 @@ INSTALL(FILES serial.hpp stream_cmd.hpp time_spec.hpp + tune_request.hpp tune_result.hpp DESTINATION ${INCLUDE_DIR}/uhd/types ) diff --git a/host/include/uhd/types/device_addr.hpp b/host/include/uhd/types/device_addr.hpp index e359d9467..eb3394230 100644 --- a/host/include/uhd/types/device_addr.hpp +++ b/host/include/uhd/types/device_addr.hpp @@ -20,6 +20,8 @@ #include <uhd/config.hpp> #include <uhd/types/dict.hpp> +#include <boost/lexical_cast.hpp> +#include <stdexcept> #include <vector> #include <string> @@ -62,6 +64,24 @@ namespace uhd{ * \return a string with delimiter markup */ std::string to_string(void) const; + + /*! + * Lexically cast a parameter to the specified type, + * or use the default value if the key is not found. + * \param key the key as one of the address parameters + * \param def the value to use when key is not present + * \return the casted value as type T or the default + * \throw error when the parameter cannot be casted + */ + template <typename T> T cast(const std::string &key, const T &def) const{ + if (not this->has_key(key)) return def; + try{ + return boost::lexical_cast<T>((*this)[key]); + } + catch(const boost::bad_lexical_cast &){ + throw std::runtime_error("cannot cast " + key + " = " + (*this)[key]); + } + } }; //handy typedef for a vector of device addresses diff --git a/host/include/uhd/types/dict.hpp b/host/include/uhd/types/dict.hpp index de96ea768..b14fc5425 100644 --- a/host/include/uhd/types/dict.hpp +++ b/host/include/uhd/types/dict.hpp @@ -19,11 +19,6 @@ #define INCLUDED_UHD_TYPES_DICT_HPP #include <uhd/config.hpp> -#include <boost/foreach.hpp> -#include <boost/format.hpp> -#include <boost/lexical_cast.hpp> -#include <stdexcept> -#include <typeinfo> #include <vector> #include <list> @@ -34,14 +29,10 @@ namespace uhd{ */ template <typename Key, typename Val> class dict{ public: - typedef std::pair<Key, Val> pair_t; - /*! * Create a new empty dictionary. */ - dict(void){ - /* NOP */ - } + dict(void); /*! * Input iterator constructor: @@ -50,64 +41,34 @@ namespace uhd{ * \param last the end iterator */ template <typename InputIterator> - dict(InputIterator first, InputIterator last){ - for(InputIterator it = first; it != last; it++){ - _map.push_back(*it); - } - } - - /*! - * Destroy this dict. - */ - ~dict(void){ - /* NOP */ - } + dict(InputIterator first, InputIterator last); /*! * Get the number of elements in this dict. * \return the number of elements */ - std::size_t size(void) const{ - return _map.size(); - } + std::size_t size(void) const; /*! * Get a list of the keys in this dict. * Key order depends on insertion precedence. * \return vector of keys */ - const std::vector<Key> keys(void) const{ - std::vector<Key> keys; - BOOST_FOREACH(const pair_t &p, _map){ - keys.push_back(p.first); - } - return keys; - } + const std::vector<Key> keys(void) const; /*! * Get a list of the values in this dict. * Value order depends on insertion precedence. * \return vector of values */ - const std::vector<Val> vals(void) const{ - std::vector<Val> vals; - BOOST_FOREACH(const pair_t &p, _map){ - vals.push_back(p.second); - } - return vals; - } + const std::vector<Val> vals(void) const; /*! * Does the dictionary contain this key? * \param key the key to look for * \return true if found */ - bool has_key(const Key &key) const{ - BOOST_FOREACH(const pair_t &p, _map){ - if (p.first == key) return true; - } - return false; - } + bool has_key(const Key &key) const; /*! * Get a value for the given key if it exists. @@ -116,15 +77,7 @@ namespace uhd{ * \return the value at the key * \throw an exception when not found */ - const Val &operator[](const Key &key) const{ - BOOST_FOREACH(const pair_t &p, _map){ - if (p.first == key) return p.second; - } - throw std::invalid_argument(str(boost::format( - "key \"%s\" not found in dict(%s, %s)" - ) % boost::lexical_cast<std::string>(key) - % typeid(Key).name() % typeid(Val).name())); - } + const Val &operator[](const Key &key) const; /*! * Set a value for the given key, however, in reality @@ -132,13 +85,7 @@ namespace uhd{ * \param key the key to set to * \return a reference to the value */ - Val &operator[](const Key &key){ - BOOST_FOREACH(pair_t &p, _map){ - if (p.first == key) return p.second; - } - _map.push_back(std::make_pair(key, Val())); - return _map.back().second; - } + Val &operator[](const Key &key); /*! * Pop an item out of the dictionary. @@ -146,16 +93,15 @@ namespace uhd{ * \return the value of the item * \throw an exception when not found */ - Val pop(const Key &key){ - Val val = (*this)[key]; - _map.remove(pair_t(key, val)); - return val; - } + Val pop(const Key &key); private: + typedef std::pair<Key, Val> pair_t; std::list<pair_t> _map; //private container }; } //namespace uhd +#include <uhd/types/dict.ipp> + #endif /* INCLUDED_UHD_TYPES_DICT_HPP */ diff --git a/host/include/uhd/types/dict.ipp b/host/include/uhd/types/dict.ipp new file mode 100644 index 000000000..85071e6fd --- /dev/null +++ b/host/include/uhd/types/dict.ipp @@ -0,0 +1,120 @@ +// +// 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 <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_UHD_TYPES_DICT_IPP +#define INCLUDED_UHD_TYPES_DICT_IPP + +#include <boost/foreach.hpp> +#include <boost/format.hpp> +#include <boost/lexical_cast.hpp> +#include <stdexcept> +#include <typeinfo> + +namespace uhd{ + + namespace /*anon*/{ + template<typename Key, typename Val> + struct UHD_API key_not_found: std::out_of_range{ + key_not_found(const Key &key): std::out_of_range( + str(boost::format( + "key \"%s\" not found in dict(%s, %s)" + ) % boost::lexical_cast<std::string>(key) + % typeid(Key).name() % typeid(Val).name() + ) + ){ + /* NOP */ + } + }; + } // namespace /*anon*/ + + template <typename Key, typename Val> + dict<Key, Val>::dict(void){ + /* NOP */ + } + + template <typename Key, typename Val> + template <typename InputIterator> + dict<Key, Val>::dict(InputIterator first, InputIterator last){ + for(InputIterator it = first; it != last; it++){ + _map.push_back(*it); + } + } + + template <typename Key, typename Val> + std::size_t dict<Key, Val>::size(void) const{ + return _map.size(); + } + + template <typename Key, typename Val> + const std::vector<Key> dict<Key, Val>::keys(void) const{ + std::vector<Key> keys; + BOOST_FOREACH(const pair_t &p, _map){ + keys.push_back(p.first); + } + return keys; + } + + template <typename Key, typename Val> + const std::vector<Val> dict<Key, Val>::vals(void) const{ + std::vector<Val> vals; + BOOST_FOREACH(const pair_t &p, _map){ + vals.push_back(p.second); + } + return vals; + } + + template <typename Key, typename Val> + bool dict<Key, Val>::has_key(const Key &key) const{ + BOOST_FOREACH(const pair_t &p, _map){ + if (p.first == key) return true; + } + return false; + } + + template <typename Key, typename Val> + const Val &dict<Key, Val>::operator[](const Key &key) const{ + BOOST_FOREACH(const pair_t &p, _map){ + if (p.first == key) return p.second; + } + throw key_not_found<Key, Val>(key); + } + + template <typename Key, typename Val> + Val &dict<Key, Val>::operator[](const Key &key){ + BOOST_FOREACH(pair_t &p, _map){ + if (p.first == key) return p.second; + } + _map.push_back(std::make_pair(key, Val())); + return _map.back().second; + } + + template <typename Key, typename Val> + Val dict<Key, Val>::pop(const Key &key){ + typename std::list<pair_t>::iterator it; + for (it = _map.begin(); it != _map.end(); it++){ + if (it->first == key){ + Val val = it->second; + _map.erase(it); + return val; + } + } + throw key_not_found<Key, Val>(key); + } + +} //namespace uhd + +#endif /* INCLUDED_UHD_TYPES_DICT_IPP */ diff --git a/host/include/uhd/types/metadata.hpp b/host/include/uhd/types/metadata.hpp index 65952941c..3f250d13e 100644 --- a/host/include/uhd/types/metadata.hpp +++ b/host/include/uhd/types/metadata.hpp @@ -19,7 +19,6 @@ #define INCLUDED_UHD_TYPES_METADATA_HPP #include <uhd/config.hpp> -#include <boost/cstdint.hpp> #include <uhd/types/time_spec.hpp> namespace uhd{ @@ -30,58 +29,59 @@ namespace uhd{ * The receive routines will convert IF data headers into metadata. */ struct UHD_API rx_metadata_t{ - /*! - * Time specification: - * Set from timestamps on incoming data when provided. - */ + //! Has time specification? bool has_time_spec; + + //! Time of the first sample. time_spec_t time_spec; /*! - * Fragmentation flag and offset: + * Fragmentation flag: * Similar to IPv4 fragmentation: http://en.wikipedia.org/wiki/IPv4#Fragmentation_and_reassembly * More fragments is true when the input buffer has insufficient size to fit * an entire received packet. More fragments will be false for the last fragment. - * The fragment offset is the sample number at the start of the receive buffer. - * For non-fragmented receives, the fragment offset should always be zero. */ bool more_fragments; - size_t fragment_offset; /*! - * Burst flags: - * Start of burst will be true for the first packet in the chain. - * End of burst will be true for the last packet in the chain. + * Fragmentation offset: + * The fragment offset is the sample number at the start of the receive buffer. + * For non-fragmented receives, the fragment offset should always be zero. */ + size_t fragment_offset; + + //! Start of burst will be true for the first packet in the chain. bool start_of_burst; + + //! End of burst will be true for the last packet in the chain. bool end_of_burst; /*! - * Error conditions: - * - none: no error associated with this metadata - * - timeout: no packet received, underlying code timed-out - * - late command: a stream command was issued in the past - * - broken chain: expected another stream command - * - overflow: an internal receive buffer has filled - * - bad packet: the buffer was unrecognizable as a vrt packet + * The error condition on a receive call. * * Note: When an overrun occurs in continuous streaming mode, * the device will continue to send samples to the host. * For other streaming modes, streaming will discontinue * until the user issues a new stream command. * - * Note: The metadata fields have meaning for the following error codes: + * The metadata fields have meaning for the following error codes: * - none * - late command * - broken chain * - overflow */ enum error_code_t { + //! No error associated with this metadata. ERROR_CODE_NONE = 0x0, + //! No packet received, implementation timed-out. ERROR_CODE_TIMEOUT = 0x1, + //! A stream command was issued in the past. ERROR_CODE_LATE_COMMAND = 0x2, + //! Expected another stream command. ERROR_CODE_BROKEN_CHAIN = 0x4, + //! An internal receive buffer has filled. ERROR_CODE_OVERFLOW = 0x8, + //! The packet could not be parsed. ERROR_CODE_BAD_PACKET = 0xf } error_code; }; @@ -93,19 +93,19 @@ namespace uhd{ */ struct UHD_API tx_metadata_t{ /*! - * Time specification: - * Set has time spec to false to perform a send "now". - * Or, set to true, and fill in time spec for a send "at". + * Has time specification? + * - Set false to send immediately. + * - Set true to send at the time specified by time spec. */ bool has_time_spec; + + //! When to send the first sample. time_spec_t time_spec; - /*! - * Burst flags: - * Set start of burst to true for the first packet in the chain. - * Set end of burst to true for the last packet in the chain. - */ + //! Set start of burst to true for the first packet in the chain. bool start_of_burst; + + //! Set end of burst to true for the last packet in the chain. bool end_of_burst; /*! @@ -122,27 +122,27 @@ namespace uhd{ //! The channel number in a mimo configuration size_t channel; - /*! - * Time specification: when the async event occurred. - */ + //! Has time specification? bool has_time_spec; + + //! When the async event occurred. time_spec_t time_spec; /*! - * Event codes: - * - success: a packet was successfully transmitted - * - underflow: an internal send buffer has emptied - * - sequence error: packet loss between host and device - * - time error: packet had time that was late (or too early) - * - underflow in packet: underflow occurred inside a packet - * - sequence error in burst: packet loss within a burst + * The type of event for a receive async message call. */ enum event_code_t { + //! A packet was successfully transmitted. EVENT_CODE_SUCCESS = 0x1, + //! An internal send buffer has emptied. EVENT_CODE_UNDERFLOW = 0x2, + //! Packet loss between host and device. EVENT_CODE_SEQ_ERROR = 0x4, + //! Packet had time that was late (or too early). EVENT_CODE_TIME_ERROR = 0x8, + //! Underflow occurred inside a packet. EVENT_CODE_UNDERFLOW_IN_PACKET = 0x10, + //! Packet loss within a burst. EVENT_CODE_SEQ_ERROR_IN_BURST = 0x20 } event_code; }; diff --git a/host/include/uhd/types/time_spec.hpp b/host/include/uhd/types/time_spec.hpp index 59b85f4b7..57d002d48 100644 --- a/host/include/uhd/types/time_spec.hpp +++ b/host/include/uhd/types/time_spec.hpp @@ -59,7 +59,7 @@ namespace uhd{ * \param tick_count the fractional seconds tick count * \param tick_rate the number of ticks per second */ - time_spec_t(time_t full_secs, size_t tick_count, double tick_rate); + time_spec_t(time_t full_secs, long tick_count, double tick_rate); /*! * Convert the fractional seconds to clock ticks. @@ -67,7 +67,7 @@ namespace uhd{ * \param tick_rate the number of ticks per second * \return the fractional seconds tick count */ - size_t get_tick_count(double tick_rate) const; + long get_tick_count(double tick_rate) const; /*! * Get the time as a real-valued seconds count. diff --git a/host/include/uhd/types/tune_request.hpp b/host/include/uhd/types/tune_request.hpp new file mode 100644 index 000000000..942b93251 --- /dev/null +++ b/host/include/uhd/types/tune_request.hpp @@ -0,0 +1,95 @@ +// +// 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 <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_UHD_TYPES_TUNE_REQUEST_HPP +#define INCLUDED_UHD_TYPES_TUNE_REQUEST_HPP + +#include <uhd/config.hpp> + +namespace uhd{ + + /*! + * A tune request instructs the implementation how to tune the RF chain. + * The policies can be used to select automatic tuning or + * fined control over the daughterboard IF and DSP tuning. + * Not all combinations of policies are applicable. + * Convenience constructors are supplied for most use cases. + */ + struct UHD_API tune_request_t{ + /*! + * Make a new tune request for a particular center frequency. + * Use an automatic policy for the intermediate and DSP frequency + * to tune the chain as close as possible to the target frequency. + * \param target_freq the target frequency in Hz + */ + tune_request_t(double target_freq = 0); + + /*! + * Make a new tune request for a particular center frequency. + * Use a manual policy for the intermediate frequency, + * and an automatic policy for the DSP frequency, + * to tune the chain as close as possible to the target frequency. + * \param target_freq the target frequency in Hz + * \param lo_off the LO offset frequency in Hz + */ + tune_request_t(double target_freq, double lo_off); + + //! Policy options for tunable elements in the RF chain. + enum policy_t { + //! Do not set this argument, use current setting. + POLICY_NONE = 'N', + //! Automatically determine the argument's value. + POLICY_AUTO = 'A', + //! Use the argument's value for the setting. + POLICY_MANUAL = 'M' + }; + + /*! + * The target frequency of the overall chain in Hz. + * Set this even if all policies are set to manual. + */ + double target_freq; + + /*! + * The policy for the intermediate frequency. + * Automatic behavior: the target frequency + default LO offset. + */ + policy_t inter_freq_policy; + + /*! + * The intermediate frequency in Hz. + * Set when the policy is set to manual. + */ + double inter_freq; + + /*! + * The policy for the DSP frequency. + * Automatic behavior: the difference between the target and IF. + */ + policy_t dsp_freq_policy; + + /*! + * The DSP frequency in Hz. + * Set when the policy is set to manual. + */ + double dsp_freq; + + }; + +} //namespace uhd + +#endif /* INCLUDED_UHD_TYPES_TUNE_REQUEST_HPP */ diff --git a/host/include/uhd/usrp/CMakeLists.txt b/host/include/uhd/usrp/CMakeLists.txt index f973e401a..abddf3951 100644 --- a/host/include/uhd/usrp/CMakeLists.txt +++ b/host/include/uhd/usrp/CMakeLists.txt @@ -42,6 +42,7 @@ INSTALL(FILES simple_usrp.hpp single_usrp.hpp mimo_usrp.hpp + multi_usrp.hpp DESTINATION ${INCLUDE_DIR}/uhd/usrp ) diff --git a/host/include/uhd/usrp/dboard_id.hpp b/host/include/uhd/usrp/dboard_id.hpp index 4c45e4334..1fda8182e 100644 --- a/host/include/uhd/usrp/dboard_id.hpp +++ b/host/include/uhd/usrp/dboard_id.hpp @@ -67,6 +67,12 @@ namespace uhd{ namespace usrp{ std::string to_string(void) const; /*! + * Get the dboard id represented as a canonical name. + * \return the canonical string representation + */ + std::string to_cname(void) const; + + /*! * Get the pretty print representation of this dboard id. * \return a string with the dboard name and id number */ diff --git a/host/include/uhd/usrp/dboard_iface.hpp b/host/include/uhd/usrp/dboard_iface.hpp index c7db244f2..c430ecd3f 100644 --- a/host/include/uhd/usrp/dboard_iface.hpp +++ b/host/include/uhd/usrp/dboard_iface.hpp @@ -242,6 +242,15 @@ public: * \param enb true for enabled */ virtual void set_clock_enabled(unit_t unit, bool enb) = 0; + + /*! + * Get the rate of the codec. + * For rx, this is the rate the ADC feeds the DSP. + * For tx, this is the rate the DSP feeds the DAC. + * \param unit which unit rx or tx + * \return the codec rate in Hz + */ + virtual double get_codec_rate(unit_t unit) = 0; }; }} //namespace diff --git a/host/include/uhd/usrp/mimo_usrp.hpp b/host/include/uhd/usrp/mimo_usrp.hpp index 10a404059..a2092f04f 100644 --- a/host/include/uhd/usrp/mimo_usrp.hpp +++ b/host/include/uhd/usrp/mimo_usrp.hpp @@ -32,12 +32,12 @@ namespace uhd{ namespace usrp{ /*! - * The MIMO USRP device class: + * The MIMO USRP device class (DEPRECATED): * A mimo usrp facilitates ease-of-use for multi-usrp scenarios. * The wrapper provides convenience functions to control the group * of underlying devices as if they consisted of a single device. */ -class UHD_API mimo_usrp : boost::noncopyable{ +class UHD_API UHD_DEPRECATED mimo_usrp : boost::noncopyable{ public: typedef boost::shared_ptr<mimo_usrp> sptr; @@ -127,7 +127,7 @@ public: virtual double get_rx_rate_all(void) = 0; virtual tune_result_t set_rx_freq(size_t chan, double freq) = 0; - virtual tune_result_t set_rx_freq(size_t chan, double freq, double lo_off) = 0; + //virtual tune_result_t set_rx_freq(size_t chan, double freq, double lo_off) = 0; virtual double get_rx_freq(size_t chan) = 0; virtual freq_range_t get_rx_freq_range(size_t chan) = 0; @@ -148,6 +148,8 @@ public: * \return the rssi in dB */ virtual float read_rssi(size_t chan) = 0; + + virtual void set_rx_bandwidth(size_t chan, float bandwidth) = 0; /******************************************************************* * TX methods @@ -159,7 +161,7 @@ public: virtual double get_tx_rate_all(void) = 0; virtual tune_result_t set_tx_freq(size_t chan, double freq) = 0; - virtual tune_result_t set_tx_freq(size_t chan, double freq, double lo_off) = 0; + //virtual tune_result_t set_tx_freq(size_t chan, double freq, double lo_off) = 0; virtual double get_tx_freq(size_t chan) = 0; virtual freq_range_t get_tx_freq_range(size_t chan) = 0; @@ -177,4 +179,347 @@ public: }} +#include <uhd/utils/warning.hpp> +#include <uhd/usrp/tune_helper.hpp> +#include <uhd/utils/assert.hpp> +#include <uhd/utils/gain_group.hpp> +#include <uhd/utils/algorithm.hpp> +#include <uhd/utils/warning.hpp> +#include <uhd/usrp/subdev_props.hpp> +#include <uhd/usrp/mboard_props.hpp> +#include <uhd/usrp/device_props.hpp> +#include <uhd/usrp/dboard_props.hpp> +#include <uhd/usrp/dsp_props.hpp> +#include <boost/foreach.hpp> +#include <boost/format.hpp> +#include <boost/thread.hpp> +#include <stdexcept> +#include <iostream> + +namespace uhd{ namespace usrp{ namespace /*anon*/{ + +static inline freq_range_t add_dsp_shift(const freq_range_t &range, wax::obj dsp){ + double codec_rate = dsp[DSP_PROP_CODEC_RATE].as<double>(); + return freq_range_t(range.min - codec_rate/2.0, range.max + codec_rate/2.0); +} + +/*********************************************************************** + * MIMO USRP Implementation + **********************************************************************/ +class mimo_usrp_impl : public mimo_usrp{ +public: + mimo_usrp_impl(const device_addr_t &addr){ + _dev = device::make(addr); + + //set the clock config across all mboards (TODO set through api) + clock_config_t clock_config; + clock_config.ref_source = clock_config_t::REF_SMA; + clock_config.pps_source = clock_config_t::PPS_SMA; + for (size_t chan = 0; chan < get_num_channels(); chan++){ + _mboard(chan)[MBOARD_PROP_CLOCK_CONFIG] = clock_config; + } + } + + ~mimo_usrp_impl(void){ + /* NOP */ + } + + device::sptr get_device(void){ + return _dev; + } + + std::string get_pp_string(void){ + std::string buff = str(boost::format( + "MIMO USRP:\n" + " Device: %s\n" + ) + % (*_dev)[DEVICE_PROP_NAME].as<std::string>() + ); + for (size_t chan = 0; chan < get_num_channels(); chan++){ + buff += str(boost::format( + " Channel: %u\n" + " Mboard: %s\n" + " RX DSP: %s\n" + " RX Dboard: %s\n" + " RX Subdev: %s\n" + " TX DSP: %s\n" + " TX Dboard: %s\n" + " TX Subdev: %s\n" + ) % chan + % _mboard(chan)[MBOARD_PROP_NAME].as<std::string>() + % _rx_dsp(chan)[DSP_PROP_NAME].as<std::string>() + % _rx_dboard(chan)[DBOARD_PROP_NAME].as<std::string>() + % _rx_subdev(chan)[SUBDEV_PROP_NAME].as<std::string>() + % _tx_dsp(chan)[DSP_PROP_NAME].as<std::string>() + % _tx_dboard(chan)[DBOARD_PROP_NAME].as<std::string>() + % _tx_subdev(chan)[SUBDEV_PROP_NAME].as<std::string>() + ); + } + return buff; + } + + size_t get_num_channels(void){ + return (*_dev)[DEVICE_PROP_MBOARD_NAMES].as<prop_names_t>().size(); + } + + /******************************************************************* + * Misc + ******************************************************************/ + time_spec_t get_time_now(void){ + //the time on the first mboard better be the same on all + return _mboard(0)[MBOARD_PROP_TIME_NOW].as<time_spec_t>(); + } + + void set_time_next_pps(const time_spec_t &time_spec){ + for (size_t chan = 0; chan < get_num_channels(); chan++){ + _mboard(chan)[MBOARD_PROP_TIME_NEXT_PPS] = time_spec; + } + } + + void set_time_unknown_pps(const time_spec_t &time_spec){ + std::cout << "Set time with unknown pps edge:" << std::endl; + std::cout << " 1) set times next pps (race condition)" << std::endl; + set_time_next_pps(time_spec); + boost::this_thread::sleep(boost::posix_time::seconds(1)); + + std::cout << " 2) catch seconds rollover at pps edge" << std::endl; + time_t last_secs = 0, curr_secs = 0; + while(curr_secs == last_secs){ + last_secs = curr_secs; + curr_secs = get_time_now().get_full_secs(); + } + + std::cout << " 3) set times next pps (synchronously)" << std::endl; + set_time_next_pps(time_spec); + boost::this_thread::sleep(boost::posix_time::seconds(1)); + + //verify that the time registers are read to be within a few RTT + for (size_t chan = 1; chan < get_num_channels(); chan++){ + time_spec_t time_0 = _mboard(0)[MBOARD_PROP_TIME_NOW].as<time_spec_t>(); + time_spec_t time_i = _mboard(chan)[MBOARD_PROP_TIME_NOW].as<time_spec_t>(); + if (time_i < time_0 or (time_i - time_0) > time_spec_t(0.01)){ //10 ms: greater than RTT but not too big + uhd::warning::post(str(boost::format( + "Detected time deviation between board %d and board 0.\n" + "Board 0 time is %f seconds.\n" + "Board %d time is %f seconds.\n" + ) % chan % time_0.get_real_secs() % chan % time_i.get_real_secs())); + } + } + } + + void issue_stream_cmd(const stream_cmd_t &stream_cmd){ + for (size_t chan = 0; chan < get_num_channels(); chan++){ + _mboard(chan)[MBOARD_PROP_STREAM_CMD] = stream_cmd; + } + } + + /******************************************************************* + * RX methods + ******************************************************************/ + void set_rx_subdev_spec(size_t chan, const subdev_spec_t &spec){ + UHD_ASSERT_THROW(spec.size() <= 1); + _mboard(chan)[MBOARD_PROP_RX_SUBDEV_SPEC] = spec; + } + + subdev_spec_t get_rx_subdev_spec(size_t chan){ + return _mboard(chan)[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>(); + } + + void set_rx_rate_all(double rate){ + std::vector<double> _actual_rates; + for (size_t chan = 0; chan < get_num_channels(); chan++){ + _rx_dsp(chan)[DSP_PROP_HOST_RATE] = rate; + _actual_rates.push_back(_rx_dsp(chan)[DSP_PROP_HOST_RATE].as<double>()); + } + _rx_rate = _actual_rates.front(); + if (std::count(_actual_rates, _rx_rate) != _actual_rates.size()) throw std::runtime_error( + "MIMO configuratio error: rx rate inconsistent across mboards" + ); + } + + double get_rx_rate_all(void){ + return _rx_rate; + } + + tune_result_t set_rx_freq(size_t chan, double target_freq){ + return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), 0, target_freq); + } + + //tune_result_t set_rx_freq(size_t chan, double target_freq, double lo_off){ + // return tune_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), 0, target_freq, lo_off); + //} + + double get_rx_freq(size_t chan){ + return derive_freq_from_rx_subdev_and_dsp(_rx_subdev(chan), _rx_dsp(chan), 0); + } + + freq_range_t get_rx_freq_range(size_t chan){ + return add_dsp_shift(_rx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _rx_dsp(chan)); + } + + void set_rx_gain(size_t chan, float gain){ + return _rx_gain_group(chan)->set_value(gain); + } + + float get_rx_gain(size_t chan){ + return _rx_gain_group(chan)->get_value(); + } + + gain_range_t get_rx_gain_range(size_t chan){ + return _rx_gain_group(chan)->get_range(); + } + + void set_rx_antenna(size_t chan, const std::string &ant){ + _rx_subdev(chan)[SUBDEV_PROP_ANTENNA] = ant; + } + + std::string get_rx_antenna(size_t chan){ + return _rx_subdev(chan)[SUBDEV_PROP_ANTENNA].as<std::string>(); + } + + std::vector<std::string> get_rx_antennas(size_t chan){ + return _rx_subdev(chan)[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>(); + } + + bool get_rx_lo_locked(size_t chan){ + return _rx_subdev(chan)[SUBDEV_PROP_LO_LOCKED].as<bool>(); + } + + float read_rssi(size_t chan){ + return _rx_subdev(chan)[SUBDEV_PROP_RSSI].as<float>(); + } + + void set_rx_bandwidth(size_t chan, float bandwidth){ + _rx_subdev(chan)[SUBDEV_PROP_BANDWIDTH] = bandwidth; + } + + /******************************************************************* + * TX methods + ******************************************************************/ + void set_tx_subdev_spec(size_t chan, const subdev_spec_t &spec){ + UHD_ASSERT_THROW(spec.size() <= 1); + _mboard(chan)[MBOARD_PROP_TX_SUBDEV_SPEC] = spec; + } + + subdev_spec_t get_tx_subdev_spec(size_t chan){ + return _mboard(chan)[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>(); + } + + void set_tx_rate_all(double rate){ + std::vector<double> _actual_rates; + for (size_t chan = 0; chan < get_num_channels(); chan++){ + _tx_dsp(chan)[DSP_PROP_HOST_RATE] = rate; + _actual_rates.push_back(_tx_dsp(chan)[DSP_PROP_HOST_RATE].as<double>()); + } + _tx_rate = _actual_rates.front(); + if (std::count(_actual_rates, _tx_rate) != _actual_rates.size()) throw std::runtime_error( + "MIMO configuratio error: tx rate inconsistent across mboards" + ); + } + + double get_tx_rate_all(void){ + return _tx_rate; + } + + tune_result_t set_tx_freq(size_t chan, double target_freq){ + return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), 0, target_freq); + } + + //tune_result_t set_tx_freq(size_t chan, double target_freq, double lo_off){ + // return tune_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), 0, target_freq, lo_off); + //} + + double get_tx_freq(size_t chan){ + return derive_freq_from_tx_subdev_and_dsp(_tx_subdev(chan), _tx_dsp(chan), 0); + } + + freq_range_t get_tx_freq_range(size_t chan){ + return add_dsp_shift(_tx_subdev(chan)[SUBDEV_PROP_FREQ_RANGE].as<freq_range_t>(), _tx_dsp(chan)); + } + + void set_tx_gain(size_t chan, float gain){ + return _tx_gain_group(chan)->set_value(gain); + } + + float get_tx_gain(size_t chan){ + return _tx_gain_group(chan)->get_value(); + } + + gain_range_t get_tx_gain_range(size_t chan){ + return _tx_gain_group(chan)->get_range(); + } + + void set_tx_antenna(size_t chan, const std::string &ant){ + _tx_subdev(chan)[SUBDEV_PROP_ANTENNA] = ant; + } + + std::string get_tx_antenna(size_t chan){ + return _tx_subdev(chan)[SUBDEV_PROP_ANTENNA].as<std::string>(); + } + + std::vector<std::string> get_tx_antennas(size_t chan){ + return _tx_subdev(chan)[SUBDEV_PROP_ANTENNA_NAMES].as<prop_names_t>(); + } + + bool get_tx_lo_locked(size_t chan){ + return _tx_subdev(chan)[SUBDEV_PROP_LO_LOCKED].as<bool>(); + } + +private: + device::sptr _dev; + wax::obj _mboard(size_t chan){ + prop_names_t names = (*_dev)[DEVICE_PROP_MBOARD_NAMES].as<prop_names_t>(); + return (*_dev)[named_prop_t(DEVICE_PROP_MBOARD, names.at(chan))]; + } + wax::obj _rx_dsp(size_t chan){ + return _mboard(chan)[MBOARD_PROP_RX_DSP]; + } + wax::obj _tx_dsp(size_t chan){ + return _mboard(chan)[MBOARD_PROP_TX_DSP]; + } + wax::obj _rx_dboard(size_t chan){ + std::string db_name = _mboard(chan)[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>().front().db_name; + return _mboard(chan)[named_prop_t(MBOARD_PROP_RX_DBOARD, db_name)]; + } + wax::obj _tx_dboard(size_t chan){ + std::string db_name = _mboard(chan)[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>().front().db_name; + return _mboard(chan)[named_prop_t(MBOARD_PROP_TX_DBOARD, db_name)]; + } + wax::obj _rx_subdev(size_t chan){ + std::string sd_name = _mboard(chan)[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name; + return _rx_dboard(chan)[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)]; + } + wax::obj _tx_subdev(size_t chan){ + std::string sd_name = _mboard(chan)[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name; + return _tx_dboard(chan)[named_prop_t(DBOARD_PROP_SUBDEV, sd_name)]; + } + gain_group::sptr _rx_gain_group(size_t chan){ + std::string sd_name = _mboard(chan)[MBOARD_PROP_RX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name; + return _rx_dboard(chan)[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as<gain_group::sptr>(); + } + gain_group::sptr _tx_gain_group(size_t chan){ + std::string sd_name = _mboard(chan)[MBOARD_PROP_TX_SUBDEV_SPEC].as<subdev_spec_t>().front().sd_name; + return _tx_dboard(chan)[named_prop_t(DBOARD_PROP_GAIN_GROUP, sd_name)].as<gain_group::sptr>(); + } + + //shadows + double _rx_rate, _tx_rate; +}; +}}} + +namespace uhd{ namespace usrp{ +/*********************************************************************** + * The Make Function + **********************************************************************/ +inline mimo_usrp::sptr mimo_usrp::make(const device_addr_t &dev_addr){ + uhd::warning::post( + "The mimo USRP interface has been deprecated.\n" + "Please switch to the multi USRP interface.\n" + "#include <uhd/usrp/multi_usrp.hpp>\n" + "multi_usrp::sptr sdev = multi_usrp::make(args);\n" + ); + return sptr(new mimo_usrp_impl(dev_addr)); +} +}} + #endif /* INCLUDED_UHD_USRP_MIMO_USRP_HPP */ diff --git a/host/include/uhd/usrp/misc_utils.hpp b/host/include/uhd/usrp/misc_utils.hpp index 2af9f5b40..37860a1a5 100644 --- a/host/include/uhd/usrp/misc_utils.hpp +++ b/host/include/uhd/usrp/misc_utils.hpp @@ -20,6 +20,7 @@ #include <uhd/config.hpp> #include <uhd/wax.hpp> +#include <uhd/usrp/dboard_id.hpp> #include <uhd/usrp/subdev_spec.hpp> #include <uhd/utils/gain_group.hpp> @@ -35,11 +36,13 @@ namespace uhd{ namespace usrp{ /*! * Create a gain group that represents the subdevice and its codec. + * \param dboard_id the dboard id for this subdevice * \param subdev the object with subdevice properties * \param codec the object with codec properties * \param gain_group_policy the policy to use */ UHD_API gain_group::sptr make_gain_group( + const dboard_id_t &dboard_id, wax::obj subdev, wax::obj codec, gain_group_policy_t gain_group_policy ); diff --git a/host/include/uhd/usrp/multi_usrp.hpp b/host/include/uhd/usrp/multi_usrp.hpp new file mode 100644 index 000000000..98ba07fc0 --- /dev/null +++ b/host/include/uhd/usrp/multi_usrp.hpp @@ -0,0 +1,530 @@ +// +// 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 <http://www.gnu.org/licenses/>. +// + +#ifndef INCLUDED_UHD_USRP_MULTI_USRP_HPP +#define INCLUDED_UHD_USRP_MULTI_USRP_HPP + +#include <uhd/config.hpp> +#include <uhd/device.hpp> +#include <uhd/types/ranges.hpp> +#include <uhd/types/stream_cmd.hpp> +#include <uhd/types/clock_config.hpp> +#include <uhd/types/tune_request.hpp> +#include <uhd/types/tune_result.hpp> +#include <uhd/usrp/subdev_spec.hpp> +#include <uhd/usrp/dboard_iface.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/utility.hpp> +#include <vector> + +namespace uhd{ namespace usrp{ + +/*! + * The multi-USRP device class: + * A multi-USRP facilitates ease-of-use for multiple USRP scenarios. + * The wrapper provides convenience functions to control the group + * of underlying devices as if they consisted of a single device. + * + * A few notes about a multi-USRP configuration: + * - All boards share a common RX sample rate + * - All boards share a common TX sample rate + * - All boards share a common RX subdevice specification size + * - All boards share a common TX subdevice specification size + * - All boards must have synchronized times (see the set_time_*() calls) + * + * Example to setup channel mapping: + * <pre> + * + * //create a multi_usrp with two boards in the configuration + * device_addr_t dev_addr; + * dev_addr["addr"] = "192.168.10.2 192.168.10.3"; + * multi_usrp::sptr dev = multi_usrp::make(dev_addr); + * + * //set the board on 10.2 to use the A RX subdevice (RX channel 0) + * dev->set_rx_subdev_spec(":A", 0); + * + * //set the board on 10.3 to use the B RX subdevice (RX channel 1) + * dev->set_rx_subdev_spec(":B", 1); + * + * //set both boards to use the AB TX subdevice (TX channels 0 and 1) + * dev->set_tx_subdev_spec(":AB", multi_usrp::ALL_MBOARDS); + * + * //now that all the channels are mapped, continue with configuration... + * + * </pre> + */ +class UHD_API multi_usrp : boost::noncopyable{ +public: + typedef boost::shared_ptr<multi_usrp> sptr; + + //! A wildcard motherboard index + static const size_t ALL_MBOARDS = size_t(~0); + + //! A wildcard gain element name + static const std::string ALL_GAINS; + + /*! + * Make a new multi usrp from the device address. + * \param dev_addr the device address + * \return a new single usrp object + */ + static sptr make(const device_addr_t &dev_addr); + + /*! + * Get the underlying device object. + * This is needed to get access to the streaming API and properties. + * \return the device object within this single usrp + */ + virtual device::sptr get_device(void) = 0; + + /******************************************************************* + * Mboard methods + ******************************************************************/ + /*! + * Get a printable summary for this USRP configuration. + * \return a printable string + */ + virtual std::string get_pp_string(void) = 0; + + /*! + * Get canonical name for this USRP motherboard. + * \param mboard which motherboard to query + * \return a string representing the name + */ + virtual std::string get_mboard_name(size_t mboard) = 0; + + /*! + * Gets the current time in the usrp time registers. + * \return a timespec representing current usrp time + */ + virtual time_spec_t get_time_now(void) = 0; + + /*! + * Set the time registers on the usrp at the next pps tick. + * The values will not be latched in until the pulse occurs. + * It is recommended that the user sleep(1) after calling to ensure + * that the time registers will be in a known state prior to use. + * + * Note: Because this call sets the time on the "next" pps, + * the seconds in the time spec should be current seconds + 1. + * + * \param time_spec the time to latch into the usrp device + */ + virtual void set_time_next_pps(const time_spec_t &time_spec) = 0; + + /*! + * Synchronize the times across all motherboards in this configuration. + * Use this method to sync the times when the edge of the PPS is unknown. + * + * Ex: Host machine is not attached to serial port of GPSDO + * and can therefore not query the GPSDO for the PPS edge. + * + * This is a 3-step process, and will take at most 3 seconds to complete. + * Upon completion, the times will be synchronized to the time provided. + * + * - Step1: set the time at the next pps (potential race condition) + * - Step2: wait for the seconds to rollover to catch the pps edge + * - Step3: set the time at the next pps (synchronous for all boards) + * + * \param time_spec the time to latch into the usrp device + */ + virtual void set_time_unknown_pps(const time_spec_t &time_spec) = 0; + + /*! + * Are the times across all motherboards in this configuration synchronized? + * Checks that all time registers are approximately close but not exact, + * given that the RTT may varying for a control packet transaction. + * \return true when all motherboards time registers are in sync + */ + virtual bool get_time_synchronized(void) = 0; + + /*! + * Issue a stream command to the usrp device. + * This tells the usrp to send samples into the host. + * See the documentation for stream_cmd_t for more info. + * \param stream_cmd the stream command to issue + */ + virtual void issue_stream_cmd(const stream_cmd_t &stream_cmd) = 0; + + /*! + * Set the clock configuration for the usrp device. + * This tells the usrp how to get a 10Mhz reference and PPS clock. + * See the documentation for clock_config_t for more info. + * \param clock_config the clock configuration to set + * \param mboard which motherboard to set the config + */ + virtual void set_clock_config(const clock_config_t &clock_config, size_t mboard) = 0; + + /*! + * Get the number of USRP motherboards in this configuration. + */ + virtual size_t get_num_mboards(void) = 0; + + /******************************************************************* + * RX methods + ******************************************************************/ + /*! + * Set the RX subdevice specification: + * The subdev spec maps a physical part of a daughter-board to a channel number. + * Set the subdev spec before calling into any methods with a channel number. + * The subdev spec must be the same size across all motherboards. + * \param spec the new subdevice specification + * \param mboard the motherboard index 0 to M-1 + */ + virtual void set_rx_subdev_spec(const uhd::usrp::subdev_spec_t &spec, size_t mboard) = 0; + + /*! + * Get the RX subdevice specification. + * \param mboard the motherboard index 0 to M-1 + * \return the subdevice specification in use + */ + virtual uhd::usrp::subdev_spec_t get_rx_subdev_spec(size_t mboard) = 0; + + /*! + * Get the number of RX channels in this configuration. + * This is the number of USRPs times the number of RX channels per board, + * where the number of RX channels per board is homogeneous among all USRPs. + */ + virtual size_t get_rx_num_channels(void) = 0; + + /*! + * Get the name of the RX subdevice. + * \param chan the channel index 0 to N-1 + * \return the subdevice name + */ + virtual std::string get_rx_subdev_name(size_t chan) = 0; + + /*! + * Set the RX sample rate across all channels. + * \param rate the rate in Sps + */ + virtual void set_rx_rate(double rate) = 0; + + /*! + * Gets the RX sample rate for all channels. + * \return the rate in Sps + */ + virtual double get_rx_rate(void) = 0; + + /*! + * Set the RX center frequency. + * \param tune_request tune request instructions + * \param chan the channel index 0 to N-1 + * \return a tune result object + */ + virtual tune_result_t set_rx_freq( + const tune_request_t &tune_request, size_t chan = 0 + ) = 0; + + /*! + * Get the RX center frequency. + * \param chan the channel index 0 to N-1 + * \return the frequency in Hz + */ + virtual double get_rx_freq(size_t chan) = 0; + + /*! + * Get the RX center frequency range. + * \param chan the channel index 0 to N-1 + * \return a frequency range object + */ + virtual freq_range_t get_rx_freq_range(size_t chan) = 0; + + /*! + * Set the RX gain value for the specified gain element. + * For an empty name, distribute across all gain elements. + * \param gain the gain in dB + * \param name the name of the gain element + * \param chan the channel index 0 to N-1 + */ + virtual void set_rx_gain(float gain, const std::string &name, size_t chan) = 0; + + //! A convenience wrapper for setting overall RX gain + void set_rx_gain(float gain, size_t chan){ + return this->set_rx_gain(gain, ALL_GAINS, chan); + } + + /*! + * Get the RX gain value for the specified gain element. + * For an empty name, sum across all gain elements. + * \param name the name of the gain element + * \param chan the channel index 0 to N-1 + * \return the gain in dB + */ + virtual float get_rx_gain(const std::string &name, size_t chan) = 0; + + //! A convenience wrapper for getting overall RX gain + float get_rx_gain(size_t chan){ + return this->get_rx_gain(ALL_GAINS, chan); + } + + /*! + * Get the RX gain range for the specified gain element. + * For an empty name, calculate the overall gain range. + * \param name the name of the gain element + * \param chan the channel index 0 to N-1 + * \return a gain range object + */ + virtual gain_range_t get_rx_gain_range(const std::string &name, size_t chan) = 0; + + //! A convenience wrapper for getting overall RX gain range + gain_range_t get_rx_gain_range(size_t chan){ + return this->get_rx_gain_range(ALL_GAINS, chan); + } + + /*! + * Get the names of the gain elements in the RX chain. + * Gain elements are ordered from antenna to FPGA. + * \param chan the channel index 0 to N-1 + * \return a vector of gain element names + */ + virtual std::vector<std::string> get_rx_gain_names(size_t chan) = 0; + + /*! + * Select the RX antenna on the subdevice. + * \param ant the antenna name + * \param chan the channel index 0 to N-1 + */ + virtual void set_rx_antenna(const std::string &ant, size_t chan) = 0; + + /*! + * Get the selected RX antenna on the subdevice. + * \param chan the channel index 0 to N-1 + * \return the antenna name + */ + virtual std::string get_rx_antenna(size_t chan) = 0; + + /*! + * Get a list of possible RX antennas on the subdevice. + * \param chan the channel index 0 to N-1 + * \return a vector of antenna names + */ + virtual std::vector<std::string> get_rx_antennas(size_t chan) = 0; + + /*! + * Get the locked status of the LO on the subdevice. + * \param chan the channel index 0 to N-1 + * \return true for locked + */ + virtual bool get_rx_lo_locked(size_t chan) = 0; + + /*! + * Set the RX bandwidth on the subdevice. + * \param bandwidth the bandwidth in Hz + * \param chan the channel index 0 to N-1 + */ + virtual void set_rx_bandwidth(double bandwidth, size_t chan) = 0; + + /*! + * Get the RX bandwidth on the subdevice. + * \param chan the channel index 0 to N-1 + * \return the bandwidth in Hz + */ + virtual double get_rx_bandwidth(size_t chan) = 0; + + /*! + * Read the RSSI value on the RX subdevice. + * \param chan the channel index 0 to N-1 + * \return the rssi in dB + * \throw exception if RSSI readback not supported + */ + virtual float read_rssi(size_t chan) = 0; + + /*! + * Get the dboard interface object for the RX subdevice. + * The dboard interface gives access to GPIOs, SPI, I2C, low-speed ADC and DAC. + * Use at your own risk! + * \param chan the channel index 0 to N-1 + * \return the dboard interface sptr + */ + virtual dboard_iface::sptr get_rx_dboard_iface(size_t chan) = 0; + + /******************************************************************* + * TX methods + ******************************************************************/ + /*! + * Set the TX subdevice specification: + * The subdev spec maps a physical part of a daughter-board to a channel number. + * Set the subdev spec before calling into any methods with a channel number. + * The subdev spec must be the same size across all motherboards. + * \param spec the new subdevice specification + * \param mboard the motherboard index 0 to M-1 + */ + virtual void set_tx_subdev_spec(const uhd::usrp::subdev_spec_t &spec, size_t mboard) = 0; + + /*! + * Get the TX subdevice specification. + * \param mboard the motherboard index 0 to M-1 + * \return the subdevice specification in use + */ + virtual uhd::usrp::subdev_spec_t get_tx_subdev_spec(size_t mboard) = 0; + + /*! + * Get the number of TX channels in this configuration. + * This is the number of USRPs times the number of TX channels per board, + * where the number of TX channels per board is homogeneous among all USRPs. + */ + virtual size_t get_tx_num_channels(void) = 0; + + /*! + * Get the name of the TX subdevice. + * \param chan the channel index 0 to N-1 + * \return the subdevice name + */ + virtual std::string get_tx_subdev_name(size_t chan) = 0; + + /*! + * Set the TX sample rate across all channels. + * \param rate the rate in Sps + */ + virtual void set_tx_rate(double rate) = 0; + + /*! + * Gets the TX sample rate for all channels. + * \return the rate in Sps + */ + virtual double get_tx_rate(void) = 0; + + /*! + * Set the TX center frequency. + * \param tune_request tune request instructions + * \param chan the channel index 0 to N-1 + * \return a tune result object + */ + virtual tune_result_t set_tx_freq( + const tune_request_t &tune_request, size_t chan = 0 + ) = 0; + + /*! + * Get the TX center frequency. + * \param chan the channel index 0 to N-1 + * \return the frequency in Hz + */ + virtual double get_tx_freq(size_t chan) = 0; + + /*! + * Get the TX center frequency range. + * \param chan the channel index 0 to N-1 + * \return a frequency range object + */ + virtual freq_range_t get_tx_freq_range(size_t chan) = 0; + + /*! + * Set the TX gain value for the specified gain element. + * For an empty name, distribute across all gain elements. + * \param gain the gain in dB + * \param name the name of the gain element + * \param chan the channel index 0 to N-1 + */ + virtual void set_tx_gain(float gain, const std::string &name, size_t chan) = 0; + + //! A convenience wrapper for setting overall TX gain + void set_tx_gain(float gain, size_t chan){ + return this->set_tx_gain(gain, ALL_GAINS, chan); + } + + /*! + * Get the TX gain value for the specified gain element. + * For an empty name, sum across all gain elements. + * \param name the name of the gain element + * \param chan the channel index 0 to N-1 + * \return the gain in dB + */ + virtual float get_tx_gain(const std::string &name, size_t chan) = 0; + + //! A convenience wrapper for getting overall TX gain + float get_tx_gain(size_t chan){ + return this->get_tx_gain(ALL_GAINS, chan); + } + + /*! + * Get the TX gain range for the specified gain element. + * For an empty name, calculate the overall gain range. + * \param name the name of the gain element + * \param chan the channel index 0 to N-1 + * \return a gain range object + */ + virtual gain_range_t get_tx_gain_range(const std::string &name, size_t chan) = 0; + + //! A convenience wrapper for getting overall TX gain range + gain_range_t get_tx_gain_range(size_t chan){ + return this->get_tx_gain_range(ALL_GAINS, chan); + } + + /*! + * Get the names of the gain elements in the TX chain. + * Gain elements are ordered from antenna to FPGA. + * \param chan the channel index 0 to N-1 + * \return a vector of gain element names + */ + virtual std::vector<std::string> get_tx_gain_names(size_t chan) = 0; + + /*! + * Select the TX antenna on the subdevice. + * \param ant the antenna name + * \param chan the channel index 0 to N-1 + */ + virtual void set_tx_antenna(const std::string &ant, size_t chan) = 0; + + /*! + * Get the selected TX antenna on the subdevice. + * \param chan the channel index 0 to N-1 + * \return the antenna name + */ + virtual std::string get_tx_antenna(size_t chan) = 0; + + /*! + * Get a list of possible TX antennas on the subdevice. + * \param chan the channel index 0 to N-1 + * \return a vector of antenna names + */ + virtual std::vector<std::string> get_tx_antennas(size_t chan) = 0; + + /*! + * Get the locked status of the LO on the subdevice. + * \param chan the channel index 0 to N-1 + * \return true for locked + */ + virtual bool get_tx_lo_locked(size_t chan) = 0; + + /*! + * Set the TX bandwidth on the subdevice. + * \param bandwidth the bandwidth in Hz + * \param chan the channel index 0 to N-1 + */ + virtual void set_tx_bandwidth(double bandwidth, size_t chan) = 0; + + /*! + * Get the TX bandwidth on the subdevice. + * \param chan the channel index 0 to N-1 + * \return the bandwidth in Hz + */ + virtual double get_tx_bandwidth(size_t chan) = 0; + + /*! + * Get the dboard interface object for the TX subdevice. + * The dboard interface gives access to GPIOs, SPI, I2C, low-speed ADC and DAC. + * Use at your own risk! + * \param chan the channel index 0 to N-1 + * \return the dboard interface sptr + */ + virtual dboard_iface::sptr get_tx_dboard_iface(size_t chan) = 0; +}; + +}} + +#endif /* INCLUDED_UHD_USRP_MULTI_USRP_HPP */ diff --git a/host/include/uhd/usrp/simple_usrp.hpp b/host/include/uhd/usrp/simple_usrp.hpp index 6149f739c..77416dbbd 100644 --- a/host/include/uhd/usrp/simple_usrp.hpp +++ b/host/include/uhd/usrp/simple_usrp.hpp @@ -117,7 +117,7 @@ public: virtual double get_rx_rate(void) = 0; virtual tune_result_t set_rx_freq(double freq) = 0; - virtual tune_result_t set_rx_freq(double freq, double lo_off) = 0; + //virtual tune_result_t set_rx_freq(double freq, double lo_off) = 0; virtual double get_rx_freq(void) = 0; virtual freq_range_t get_rx_freq_range(void) = 0; @@ -139,6 +139,8 @@ public: virtual float read_rssi(void) = 0; virtual dboard_iface::sptr get_rx_dboard_iface(void) = 0; + + virtual void set_rx_bandwidth(float) = 0; /******************************************************************* * TX methods @@ -150,7 +152,7 @@ public: virtual double get_tx_rate(void) = 0; virtual tune_result_t set_tx_freq(double freq) = 0; - virtual tune_result_t set_tx_freq(double freq, double lo_off) = 0; + //virtual tune_result_t set_tx_freq(double freq, double lo_off) = 0; virtual double get_tx_freq(void) = 0; virtual freq_range_t get_tx_freq_range(void) = 0; @@ -169,4 +171,218 @@ public: }} +#include <uhd/usrp/single_usrp.hpp> +#include <uhd/utils/warning.hpp> + +namespace uhd{ namespace usrp{ namespace /*anon*/{ + +/*********************************************************************** + * Simple USRP Implementation + **********************************************************************/ +class simple_usrp_impl : public simple_usrp{ +public: + simple_usrp_impl(const device_addr_t &addr){ + _sdev = single_usrp::make(addr); + } + + ~simple_usrp_impl(void){ + /* NOP */ + } + + device::sptr get_device(void){ + return _sdev->get_device(); + } + + std::string get_pp_string(void){ + return _sdev->get_pp_string(); + } + + /******************************************************************* + * Misc + ******************************************************************/ + time_spec_t get_time_now(void){ + return _sdev->get_time_now(); + } + + void set_time_now(const time_spec_t &time_spec){ + return _sdev->set_time_now(time_spec); + } + + void set_time_next_pps(const time_spec_t &time_spec){ + return _sdev->set_time_next_pps(time_spec); + } + + void issue_stream_cmd(const stream_cmd_t &stream_cmd){ + return _sdev->issue_stream_cmd(stream_cmd); + } + + void set_clock_config(const clock_config_t &clock_config){ + return _sdev->set_clock_config(clock_config); + } + + /******************************************************************* + * RX methods + ******************************************************************/ + void set_rx_subdev_spec(const subdev_spec_t &spec){ + return _sdev->set_rx_subdev_spec(spec); + } + + subdev_spec_t get_rx_subdev_spec(void){ + return _sdev->get_rx_subdev_spec(); + } + + void set_rx_rate(double rate){ + return _sdev->set_rx_rate(rate); + } + + double get_rx_rate(void){ + return _sdev->get_rx_rate(); + } + + tune_result_t set_rx_freq(double target_freq){ + return _sdev->set_rx_freq(target_freq); + } + + //tune_result_t set_rx_freq(double target_freq, double lo_off){ + // return _sdev->set_rx_freq(target_freq, lo_off); + //} + + double get_rx_freq(void){ + return _sdev->get_rx_freq(); + } + + freq_range_t get_rx_freq_range(void){ + return _sdev->get_rx_freq_range(); + } + + void set_rx_gain(float gain){ + return _sdev->set_rx_gain(gain); + } + + float get_rx_gain(void){ + return _sdev->get_rx_gain(); + } + + gain_range_t get_rx_gain_range(void){ + return _sdev->get_rx_gain_range(); + } + + void set_rx_antenna(const std::string &ant){ + return _sdev->set_rx_antenna(ant); + } + + std::string get_rx_antenna(void){ + return _sdev->get_rx_antenna(); + } + + std::vector<std::string> get_rx_antennas(void){ + return _sdev->get_rx_antennas(); + } + + bool get_rx_lo_locked(void){ + return _sdev->get_rx_lo_locked(); + } + + float read_rssi(void){ + return _sdev->read_rssi(); + } + + dboard_iface::sptr get_rx_dboard_iface(void){ + return _sdev->get_rx_dboard_iface(); + } + + void set_rx_bandwidth(float bandwidth) { + return _sdev->set_rx_bandwidth(bandwidth); + } + + /******************************************************************* + * TX methods + ******************************************************************/ + void set_tx_subdev_spec(const subdev_spec_t &spec){ + return _sdev->set_tx_subdev_spec(spec); + } + + subdev_spec_t get_tx_subdev_spec(void){ + return _sdev->get_tx_subdev_spec(); + } + + void set_tx_rate(double rate){ + return _sdev->set_tx_rate(rate); + } + + double get_tx_rate(void){ + return _sdev->get_tx_rate(); + } + + tune_result_t set_tx_freq(double target_freq){ + return _sdev->set_tx_freq(target_freq); + } + + //tune_result_t set_tx_freq(double target_freq, double lo_off){ + // return _sdev->set_tx_freq(target_freq, lo_off); + //} + + double get_tx_freq(void){ + return _sdev->get_tx_freq(); + } + + freq_range_t get_tx_freq_range(void){ + return _sdev->get_tx_freq_range(); + } + + void set_tx_gain(float gain){ + return _sdev->set_tx_gain(gain); + } + + float get_tx_gain(void){ + return _sdev->get_tx_gain(); + } + + gain_range_t get_tx_gain_range(void){ + return _sdev->get_tx_gain_range(); + } + + void set_tx_antenna(const std::string &ant){ + return _sdev->set_tx_antenna(ant); + } + + std::string get_tx_antenna(void){ + return _sdev->get_tx_antenna(); + } + + std::vector<std::string> get_tx_antennas(void){ + return _sdev->get_tx_antennas(); + } + + bool get_tx_lo_locked(void){ + return _sdev->get_tx_lo_locked(); + } + + dboard_iface::sptr get_tx_dboard_iface(void){ + return _sdev->get_tx_dboard_iface(); + } + +private: + single_usrp::sptr _sdev; +}; + +}}} + +namespace uhd{ namespace usrp{ + +/*********************************************************************** + * The Make Function + **********************************************************************/ +inline simple_usrp::sptr simple_usrp::make(const device_addr_t &dev_addr){ + uhd::warning::post( + "The simple USRP interface has been deprecated.\n" + "Please switch to the single USRP interface.\n" + "#include <uhd/usrp/single_usrp.hpp>\n" + "single_usrp::sptr sdev = single_usrp::make(args);\n" + ); + return sptr(new simple_usrp_impl(dev_addr)); +} + +}} + #endif /* INCLUDED_UHD_USRP_SIMPLE_USRP_HPP */ diff --git a/host/include/uhd/usrp/single_usrp.hpp b/host/include/uhd/usrp/single_usrp.hpp index 1b89a3620..26303fe10 100644 --- a/host/include/uhd/usrp/single_usrp.hpp +++ b/host/include/uhd/usrp/single_usrp.hpp @@ -23,6 +23,7 @@ #include <uhd/types/ranges.hpp> #include <uhd/types/stream_cmd.hpp> #include <uhd/types/clock_config.hpp> +#include <uhd/types/tune_request.hpp> #include <uhd/types/tune_result.hpp> #include <uhd/usrp/subdev_spec.hpp> #include <uhd/usrp/dboard_iface.hpp> @@ -33,8 +34,8 @@ namespace uhd{ namespace usrp{ /*! - * The single USRP device class: - * A single usrp facilitates ease-of-use for most use-case scenarios. + * The single-USRP device class: + * A single-USRP facilitates ease-of-use for most use-case scenarios. * The wrapper provides convenience functions to tune the devices * as well as to set the dboard gains, antennas, and other properties. * This wrapper supports multi-channel configurations per motherboard. @@ -43,6 +44,9 @@ class UHD_API single_usrp : boost::noncopyable{ public: typedef boost::shared_ptr<single_usrp> sptr; + //! A wildcard gain element name + static const std::string ALL_GAINS; + /*! * Make a new single usrp from the device address. * \param dev_addr the device address @@ -57,15 +61,21 @@ public: */ virtual device::sptr get_device(void) = 0; + /******************************************************************* + * Mboard methods + ******************************************************************/ /*! - * Get a printable name for this usrp. + * Get a printable summary for this USRP configuration. * \return a printable string */ virtual std::string get_pp_string(void) = 0; - /******************************************************************* - * Misc - ******************************************************************/ + /*! + * Get canonical name for this USRP motherboard. + * \return a string representing the name + */ + virtual std::string get_mboard_name(void) = 0; + /*! * Gets the current time in the usrp time registers. * \return a timespec representing current usrp time @@ -110,60 +120,331 @@ public: /******************************************************************* * RX methods ******************************************************************/ + /*! + * Set the RX subdevice specification: + * The subdev spec maps a physical part of a daughter-board to a channel number. + * Set the subdev spec before calling into any methods with a channel number. + * \param spec the new subdevice specification + */ virtual void set_rx_subdev_spec(const uhd::usrp::subdev_spec_t &spec) = 0; + + /*! + * Get the RX subdevice specification. + * \return the subdevice specification in use + */ virtual uhd::usrp::subdev_spec_t get_rx_subdev_spec(void) = 0; + /*! + * Get the name of the RX subdevice. + * \param chan the channel index 0 to N-1 + * \return the subdevice name + */ + virtual std::string get_rx_subdev_name(size_t chan = 0) = 0; + + /*! + * Set the RX sample rate across all channels. + * \param rate the rate in Sps + */ virtual void set_rx_rate(double rate) = 0; + + /*! + * Gets the RX sample rate for all channels. + * \return the rate in Sps + */ virtual double get_rx_rate(void) = 0; - virtual tune_result_t set_rx_freq(double freq, size_t chan = 0) = 0; - virtual tune_result_t set_rx_freq(double freq, double lo_off, size_t chan = 0) = 0; + /*! + * Set the RX center frequency. + * \param tune_request tune request instructions + * \param chan the channel index 0 to N-1 + * \return a tune result object + */ + virtual tune_result_t set_rx_freq( + const tune_request_t &tune_request, size_t chan = 0 + ) = 0; + + /*! + * Get the RX center frequency. + * \param chan the channel index 0 to N-1 + * \return the frequency in Hz + */ virtual double get_rx_freq(size_t chan = 0) = 0; + + /*! + * Get the RX center frequency range. + * \param chan the channel index 0 to N-1 + * \return a frequency range object + */ virtual freq_range_t get_rx_freq_range(size_t chan = 0) = 0; - virtual void set_rx_gain(float gain, size_t chan = 0) = 0; - virtual float get_rx_gain(size_t chan = 0) = 0; - virtual gain_range_t get_rx_gain_range(size_t chan = 0) = 0; + /*! + * Set the RX gain value for the specified gain element. + * For an empty name, distribute across all gain elements. + * \param gain the gain in dB + * \param name the name of the gain element + * \param chan the channel index 0 to N-1 + */ + virtual void set_rx_gain(float gain, const std::string &name, size_t chan = 0) = 0; + + //! A convenience wrapper for setting overall RX gain + void set_rx_gain(float gain, size_t chan = 0){ + return this->set_rx_gain(gain, ALL_GAINS, chan); + } + + /*! + * Get the RX gain value for the specified gain element. + * For an empty name, sum across all gain elements. + * \param name the name of the gain element + * \param chan the channel index 0 to N-1 + * \return the gain in dB + */ + virtual float get_rx_gain(const std::string &name, size_t chan = 0) = 0; + + //! A convenience wrapper for getting overall RX gain + float get_rx_gain(size_t chan = 0){ + return this->get_rx_gain(ALL_GAINS, chan); + } + + /*! + * Get the RX gain range for the specified gain element. + * For an empty name, calculate the overall gain range. + * \param name the name of the gain element + * \param chan the channel index 0 to N-1 + * \return a gain range object + */ + virtual gain_range_t get_rx_gain_range(const std::string &name, size_t chan = 0) = 0; + + //! A convenience wrapper for getting overall RX gain range + gain_range_t get_rx_gain_range(size_t chan = 0){ + return this->get_rx_gain_range(ALL_GAINS, chan); + } + + /*! + * Get the names of the gain elements in the RX chain. + * Gain elements are ordered from antenna to FPGA. + * \param chan the channel index 0 to N-1 + * \return a vector of gain element names + */ + virtual std::vector<std::string> get_rx_gain_names(size_t chan = 0) = 0; + /*! + * Select the RX antenna on the subdevice. + * \param ant the antenna name + * \param chan the channel index 0 to N-1 + */ virtual void set_rx_antenna(const std::string &ant, size_t chan = 0) = 0; + + /*! + * Get the selected RX antenna on the subdevice. + * \param chan the channel index 0 to N-1 + * \return the antenna name + */ virtual std::string get_rx_antenna(size_t chan = 0) = 0; + + /*! + * Get a list of possible RX antennas on the subdevice. + * \param chan the channel index 0 to N-1 + * \return a vector of antenna names + */ virtual std::vector<std::string> get_rx_antennas(size_t chan = 0) = 0; + /*! + * Get the locked status of the LO on the subdevice. + * \param chan the channel index 0 to N-1 + * \return true for locked + */ virtual bool get_rx_lo_locked(size_t chan = 0) = 0; /*! - * Read the RSSI value from a usrp device. - * Or throw if the dboard does not support an RSSI readback. + * Set the RX bandwidth on the subdevice. + * \param bandwidth the bandwidth in Hz + * \param chan the channel index 0 to N-1 + */ + virtual void set_rx_bandwidth(double bandwidth, size_t chan = 0) = 0; + + /*! + * Get the RX bandwidth on the subdevice. + * \param chan the channel index 0 to N-1 + * \return the bandwidth in Hz + */ + virtual double get_rx_bandwidth(size_t chan = 0) = 0; + + /*! + * Read the RSSI value on the RX subdevice. + * \param chan the channel index 0 to N-1 * \return the rssi in dB + * \throw exception if RSSI readback not supported */ virtual float read_rssi(size_t chan = 0) = 0; + /*! + * Get the dboard interface object for the RX subdevice. + * The dboard interface gives access to GPIOs, SPI, I2C, low-speed ADC and DAC. + * Use at your own risk! + * \param chan the channel index 0 to N-1 + * \return the dboard interface sptr + */ virtual dboard_iface::sptr get_rx_dboard_iface(size_t chan = 0) = 0; /******************************************************************* * TX methods ******************************************************************/ + /*! + * Set the TX subdevice specification: + * The subdev spec maps a physical part of a daughter-board to a channel number. + * Set the subdev spec before calling into any methods with a channel number. + * \param spec the new subdevice specification + */ virtual void set_tx_subdev_spec(const uhd::usrp::subdev_spec_t &spec) = 0; + + /*! + * Get the TX subdevice specification. + * \return the subdevice specification in use + */ virtual uhd::usrp::subdev_spec_t get_tx_subdev_spec(void) = 0; + /*! + * Get the name of the TX subdevice. + * \param chan the channel index 0 to N-1 + * \return the subdevice name + */ + virtual std::string get_tx_subdev_name(size_t chan = 0) = 0; + + /*! + * Set the TX sample rate across all channels. + * \param rate the rate in Sps + */ virtual void set_tx_rate(double rate) = 0; + + /*! + * Gets the TX sample rate for all channels. + * \return the rate in Sps + */ virtual double get_tx_rate(void) = 0; - virtual tune_result_t set_tx_freq(double freq, size_t chan = 0) = 0; - virtual tune_result_t set_tx_freq(double freq, double lo_off, size_t chan = 0) = 0; + /*! + * Set the TX center frequency. + * \param tune_request tune request instructions + * \param chan the channel index 0 to N-1 + * \return a tune result object + */ + virtual tune_result_t set_tx_freq( + const tune_request_t &tune_request, size_t chan = 0 + ) = 0; + + /*! + * Get the TX center frequency. + * \param chan the channel index 0 to N-1 + * \return the frequency in Hz + */ virtual double get_tx_freq(size_t chan = 0) = 0; + + /*! + * Get the TX center frequency range. + * \param chan the channel index 0 to N-1 + * \return a frequency range object + */ virtual freq_range_t get_tx_freq_range(size_t chan = 0) = 0; - virtual void set_tx_gain(float gain, size_t chan = 0) = 0; - virtual float get_tx_gain(size_t chan = 0) = 0; - virtual gain_range_t get_tx_gain_range(size_t chan = 0) = 0; + /*! + * Set the TX gain value for the specified gain element. + * For an empty name, distribute across all gain elements. + * \param gain the gain in dB + * \param name the name of the gain element + * \param chan the channel index 0 to N-1 + */ + virtual void set_tx_gain(float gain, const std::string &name, size_t chan = 0) = 0; + + //! A convenience wrapper for setting overall TX gain + void set_tx_gain(float gain, size_t chan = 0){ + return this->set_tx_gain(gain, ALL_GAINS, chan); + } + /*! + * Get the TX gain value for the specified gain element. + * For an empty name, sum across all gain elements. + * \param name the name of the gain element + * \param chan the channel index 0 to N-1 + * \return the gain in dB + */ + virtual float get_tx_gain(const std::string &name, size_t chan = 0) = 0; + + //! A convenience wrapper for getting overall TX gain + float get_tx_gain(size_t chan = 0){ + return this->get_tx_gain(ALL_GAINS, chan); + } + + /*! + * Get the TX gain range for the specified gain element. + * For an empty name, calculate the overall gain range. + * \param name the name of the gain element + * \param chan the channel index 0 to N-1 + * \return a gain range object + */ + virtual gain_range_t get_tx_gain_range(const std::string &name, size_t chan = 0) = 0; + + //! A convenience wrapper for getting overall TX gain range + gain_range_t get_tx_gain_range(size_t chan = 0){ + return this->get_tx_gain_range(ALL_GAINS, chan); + } + + /*! + * Get the names of the gain elements in the TX chain. + * Gain elements are ordered from antenna to FPGA. + * \param chan the channel index 0 to N-1 + * \return a vector of gain element names + */ + virtual std::vector<std::string> get_tx_gain_names(size_t chan = 0) = 0; + + /*! + * Select the TX antenna on the subdevice. + * \param ant the antenna name + * \param chan the channel index 0 to N-1 + */ virtual void set_tx_antenna(const std::string &ant, size_t chan = 0) = 0; + + /*! + * Get the selected TX antenna on the subdevice. + * \param chan the channel index 0 to N-1 + * \return the antenna name + */ virtual std::string get_tx_antenna(size_t chan = 0) = 0; + + /*! + * Get a list of possible TX antennas on the subdevice. + * \param chan the channel index 0 to N-1 + * \return a vector of antenna names + */ virtual std::vector<std::string> get_tx_antennas(size_t chan = 0) = 0; + /*! + * Get the locked status of the LO on the subdevice. + * \param chan the channel index 0 to N-1 + * \return true for locked + */ virtual bool get_tx_lo_locked(size_t chan = 0) = 0; + /*! + * Set the TX bandwidth on the subdevice. + * \param bandwidth the bandwidth in Hz + * \param chan the channel index 0 to N-1 + */ + virtual void set_tx_bandwidth(double bandwidth, size_t chan = 0) = 0; + + /*! + * Get the TX bandwidth on the subdevice. + * \param chan the channel index 0 to N-1 + * \return the bandwidth in Hz + */ + virtual double get_tx_bandwidth(size_t chan = 0) = 0; + + /*! + * Get the dboard interface object for the TX subdevice. + * The dboard interface gives access to GPIOs, SPI, I2C, low-speed ADC and DAC. + * Use at your own risk! + * \param chan the channel index 0 to N-1 + * \return the dboard interface sptr + */ virtual dboard_iface::sptr get_tx_dboard_iface(size_t chan = 0) = 0; }; diff --git a/host/include/uhd/usrp/subdev_props.hpp b/host/include/uhd/usrp/subdev_props.hpp index cd07cb7a8..8f096ffe4 100644 --- a/host/include/uhd/usrp/subdev_props.hpp +++ b/host/include/uhd/usrp/subdev_props.hpp @@ -53,6 +53,7 @@ namespace uhd{ namespace usrp{ SUBDEV_PROP_ANTENNA_NAMES = 'A', //ro, prop_names_t SUBDEV_PROP_LO_LOCKED = 'L', //ro, bool SUBDEV_PROP_CONNECTION = 'c', //ro, subdev_conn_t + SUBDEV_PROP_ENABLED = 'e', //rw, bool SUBDEV_PROP_USE_LO_OFFSET = 'l', //ro, bool SUBDEV_PROP_RSSI = 'R', //ro, float SUBDEV_PROP_BANDWIDTH = 'B' //rw, double diff --git a/host/include/uhd/usrp/subdev_spec.hpp b/host/include/uhd/usrp/subdev_spec.hpp index 2f32509b9..b189724c9 100644 --- a/host/include/uhd/usrp/subdev_spec.hpp +++ b/host/include/uhd/usrp/subdev_spec.hpp @@ -19,16 +19,17 @@ #define INCLUDED_UHD_USRP_SUBDEV_SPEC_HPP #include <uhd/config.hpp> +#include <boost/operators.hpp> #include <vector> #include <string> namespace uhd{ namespace usrp{ /*! - * A subdevice specification (daughterboard, subdevice) name pairing. + * A subdevice specification (daughterboard slot, subdevice) name pairing. */ - struct UHD_API subdev_spec_pair_t{ - //! The daughterboard name + struct UHD_API subdev_spec_pair_t : boost::equality_comparable<subdev_spec_pair_t>{ + //! The daughterboard slot name std::string db_name; //! The subdevice name @@ -45,8 +46,11 @@ namespace uhd{ namespace usrp{ ); }; + //! overloaded comparison operator for subdev_spec_pair_t + UHD_API bool operator==(const subdev_spec_pair_t &, const subdev_spec_pair_t &); + /*! - * A list of (daughterboard name, subdevice name) pairs: + * A list of (daughterboard slot name, subdevice name) pairs: * * A subdevice specification represents a list of subdevices on a motherboard. * The subdevices specified may span across multiple daughterboards; @@ -58,6 +62,11 @@ namespace uhd{ namespace usrp{ * The markup-string is a whitespace separated list of dboard:subdev pairs. * The first pair represents the subdevice for channel zero, * the second pair represents the subdevice for channel one, and so on. + * + * Special handling for empty conditions: + * - An empty subdevice specification means: select the first subdevice found in the configuration + * - An empty daughterboard name means: select the only daughterboard slot or error if multiple exist + * - An empty subdevice name means: select the only subdevice on that board or error if multiple exist */ class UHD_API subdev_spec_t : public std::vector<subdev_spec_pair_t>{ public: diff --git a/host/include/uhd/usrp/tune_helper.hpp b/host/include/uhd/usrp/tune_helper.hpp index ec133fa08..db12241c1 100644 --- a/host/include/uhd/usrp/tune_helper.hpp +++ b/host/include/uhd/usrp/tune_helper.hpp @@ -20,6 +20,7 @@ #include <uhd/config.hpp> #include <uhd/wax.hpp> +#include <uhd/types/tune_request.hpp> #include <uhd/types/tune_result.hpp> namespace uhd{ namespace usrp{ @@ -32,23 +33,12 @@ namespace uhd{ namespace usrp{ * \param subdev the dboard subdevice object with properties * \param ddc the mboard dsp object with properties * \param chan the channel of the dsp to tune - * \param target_freq the desired center frequency - * \param lo_offset an offset for the subdevice IF from center + * \param tune_request tune request instructions * \return a tune result struct */ UHD_API tune_result_t tune_rx_subdev_and_dsp( wax::obj subdev, wax::obj ddc, size_t chan, - double target_freq, double lo_offset - ); - - /*! - * Tune a rx chain to the desired frequency: - * Same as the above, except the LO offset - * is calculated based on the subdevice and BW. - */ - UHD_API tune_result_t tune_rx_subdev_and_dsp( - wax::obj subdev, wax::obj ddc, - size_t chan, double target_freq + const tune_request_t &tune_request ); /*! @@ -70,23 +60,12 @@ namespace uhd{ namespace usrp{ * \param subdev the dboard subdevice object with properties * \param duc the mboard dsp object with properties * \param chan the channel of the dsp to tune - * \param target_freq the desired center frequency - * \param lo_offset an offset for the subdevice IF from center + * \param tune_request tune request instructions * \return a tune result struct */ UHD_API tune_result_t tune_tx_subdev_and_dsp( wax::obj subdev, wax::obj duc, size_t chan, - double target_freq, double lo_offset - ); - - /*! - * Tune a tx chain to the desired frequency: - * Same as the above, except the LO offset - * is calculated based on the subdevice and BW. - */ - UHD_API tune_result_t tune_tx_subdev_and_dsp( - wax::obj subdev, wax::obj duc, - size_t chan, double target_freq + const tune_request_t &tune_request ); /*! diff --git a/host/include/uhd/utils/gain_group.hpp b/host/include/uhd/utils/gain_group.hpp index 3955dfa9a..c863248ce 100644 --- a/host/include/uhd/utils/gain_group.hpp +++ b/host/include/uhd/utils/gain_group.hpp @@ -23,6 +23,8 @@ #include <boost/shared_ptr.hpp> #include <boost/function.hpp> #include <boost/utility.hpp> +#include <vector> +#include <string> namespace uhd{ @@ -40,36 +42,57 @@ public: typedef boost::shared_ptr<gain_group> sptr; /*! - * Get the overall gain range for this group. + * Get the gain range for the gain element specified by name. + * For an empty name, get the overall gain range for this group. * Overall step is defined as the minimum step size. + * \param name name of the gain element (optional) * \return a gain range with overall min, max, step */ - virtual gain_range_t get_range(void) = 0; + virtual gain_range_t get_range(const std::string &name = "") = 0; /*! - * Get the overall gain value for this group. - * \return a summation of all the gain values + * Get the gain value for the gain element specified by name. + * For an empty name, get the overall gain value for this group. + * \param name name of the gain element (optional) + * \return a gain value of the element or all elements */ - virtual float get_value(void) = 0; + virtual float get_value(const std::string &name = "") = 0; /*! - * Set the overall gain value for this group. + * Set the gain value for the gain element specified by name. + * For an empty name, set the overall gain value for this group. * The power will be distributed across individual gain elements. * The semantics of how to do this are determined by the priority. - * \param gain the gain to set across the group + * \param gain the gain to set for the lement or across the group + * \param name name of the gain element (optional) */ - virtual void set_value(float gain) = 0; + virtual void set_value(float gain, const std::string &name = "") = 0; /*! - * Register a set of gain functions into this group. + * Get a list of names of registered gain elements. + * The names are in the order that they were registered. + * \return a vector of gain name strings + */ + virtual const std::vector<std::string> get_names(void) = 0; + + /*! + * Register a set of gain functions into this group: + * + * The name should be a unique and non-empty name. + * Othwerwise, the implementation will rename it. + * * Priority determines how power will be distributed * with higher priorities getting the power first, * and lower priorities getting the remainder power. + * + * \param name the name of the gain element * \param gain_fcns the set of gain functions * \param priority the priority of the gain element */ virtual void register_fcns( - const gain_fcns_t &gain_fcns, size_t priority = 0 + const std::string &name, + const gain_fcns_t &gain_fcns, + size_t priority = 0 ) = 0; /*! diff --git a/host/include/uhd/utils/warning.hpp b/host/include/uhd/utils/warning.hpp index 91d8400ab..a1e3f0d1e 100644 --- a/host/include/uhd/utils/warning.hpp +++ b/host/include/uhd/utils/warning.hpp @@ -19,16 +19,44 @@ #define INCLUDED_UHD_UTILS_WARNING_HPP #include <uhd/config.hpp> +#include <boost/function.hpp> +#include <vector> #include <string> -namespace uhd{ +namespace uhd{ namespace warning{ + + //! Callback function type for a message handler + typedef boost::function<void(std::string)> handler_t; /*! - * Print a formatted warning string to stderr. + * Post a warning message to all registered handlers. * \param msg the multiline warning message */ - UHD_API void print_warning(const std::string &msg); + UHD_API void post(const std::string &msg); + + /*! + * Register a new handler with this name. + * If the name was already registered for this name, + * the old registered handler will be replaced. + * \param name a unique name for this handler + * \param handler the callback handler function + */ + UHD_API void register_handler(const std::string &name, const handler_t &handler); + + /*! + * Unregister a handler for this name. + * \param name a unique name for a registered handler + * \return the handler that was registered + * \throw error when the name was not found in the registry + */ + UHD_API handler_t unregister_handler(const std::string &name); + + /*! + * Get a list of registered handler names. + * \return a vector of unique string names + */ + UHD_API const std::vector<std::string> registry_names(void); -} //namespace uhd +}} //namespace uhd::warning #endif /* INCLUDED_UHD_UTILS_WARNING_HPP */ |