diff options
Diffstat (limited to 'host/include')
25 files changed, 1361 insertions, 25 deletions
diff --git a/host/include/uhd/config.hpp b/host/include/uhd/config.hpp index 7ecc4924a..8939cd773 100644 --- a/host/include/uhd/config.hpp +++ b/host/include/uhd/config.hpp @@ -1,5 +1,5 @@ // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-2011,2014-2015 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 @@ -56,6 +56,13 @@ typedef ptrdiff_t ssize_t; #define UHD_DEPRECATED __declspec(deprecated) #define UHD_ALIGNED(x) __declspec(align(x)) #define UHD_UNUSED(x) x +#elif defined(__MINGW32__) + #define UHD_EXPORT __declspec(dllexport) + #define UHD_IMPORT __declspec(dllimport) + #define UHD_INLINE inline + #define UHD_DEPRECATED __declspec(deprecated) + #define UHD_ALIGNED(x) __declspec(align(x)) + #define UHD_UNUSED(x) x __attribute__((unused)) #elif defined(__GNUG__) && __GNUG__ >= 4 #define UHD_EXPORT __attribute__((visibility("default"))) #define UHD_IMPORT __attribute__((visibility("default"))) diff --git a/host/include/uhd/convert.hpp b/host/include/uhd/convert.hpp index d740d80fb..e42123b20 100644 --- a/host/include/uhd/convert.hpp +++ b/host/include/uhd/convert.hpp @@ -63,12 +63,13 @@ namespace uhd{ namespace convert{ typedef int priority_type; //! Identify a conversion routine in the registry - struct id_type : boost::equality_comparable<id_type>{ + struct UHD_API id_type : boost::equality_comparable<id_type>{ std::string input_format; size_t num_inputs; std::string output_format; size_t num_outputs; std::string to_pp_string(void) const; + std::string to_string(void) const; }; //! Implement equality_comparable interface diff --git a/host/include/uhd/exception.hpp b/host/include/uhd/exception.hpp index 69e902fd5..a21106166 100644 --- a/host/include/uhd/exception.hpp +++ b/host/include/uhd/exception.hpp @@ -98,6 +98,14 @@ namespace uhd{ virtual void dynamic_throw(void) const; }; + struct UHD_API usb_error : runtime_error{ + int _code; + usb_error(int code, const std::string &what); + virtual unsigned code(void) const { return _code; }; + virtual usb_error *dynamic_clone(void) const; + virtual void dynamic_throw(void) const; + }; + struct UHD_API not_implemented_error : runtime_error{ not_implemented_error(const std::string &what); virtual unsigned code(void) const; diff --git a/host/include/uhd/image_loader.hpp b/host/include/uhd/image_loader.hpp new file mode 100644 index 000000000..8124e7dea --- /dev/null +++ b/host/include/uhd/image_loader.hpp @@ -0,0 +1,89 @@ +// +// Copyright 2014-2015 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_IMAGE_LOADER_HPP +#define INCLUDED_UHD_IMAGE_LOADER_HPP + +#include <string> + +#include <boost/function.hpp> + +#include <uhd/config.hpp> +#include <uhd/types/device_addr.hpp> + +namespace uhd{ + +class UHD_API image_loader : boost::noncopyable{ + +public: + + typedef struct{ + uhd::device_addr_t args; + bool load_firmware; + bool load_fpga; + std::string firmware_path; + std::string fpga_path; + } image_loader_args_t; + + //! Signature of an image loading function + /*! + * This is the function signature for an image loading function. + * See the declaration of load() for the meaning of these arguments. + * + * This function must return true upon the end of a successful image load + * or false if no applicable device was found. It may only throw a runtime + * error under one of two conditions: + * + * * The function has already engaged with a specific device and + * something goes wrong. + * * The user gives arguments that unambiguously lead to a specific + * device and expect the default image(s) to be loaded, but the specific + * model of the device cannot be determined beyond a category. + */ + typedef boost::function<bool(const image_loader_args_t &)> loader_fcn_t; + + //! Register an image loader + /*! + * \param device_type the "type=foo" value given in an --args option + * \param loader_fcn the loader function for the given device + * \param recovery_instructions instructions on how to restore a device + */ + static void register_image_loader( + const std::string &device_type, + const loader_fcn_t &loader_fcn, + const std::string &recovery_instructions + ); + + //! Load firmware and/or FPGA onto a device + /*! + * \param image_loader_args arguments to pass into image loading function + */ + static bool load(const image_loader_args_t &image_loader_args); + + //! Get the instructions on how to recovery a particular device + /*! + * These instructions should be queried if the user interrupts an image loading + * session, as this will likely leave the device in an unstable state. + * \param device_type the "type=foo" value given in an --args option + * \return recoverying instructions + */ + static std::string get_recovery_instructions(const std::string &device_type); +}; + +} + +#endif /* INCLUDED_UHD_IMAGE_LOADER_HPP */ diff --git a/host/include/uhd/transport/CMakeLists.txt b/host/include/uhd/transport/CMakeLists.txt index 2118674c6..623c179e9 100644 --- a/host/include/uhd/transport/CMakeLists.txt +++ b/host/include/uhd/transport/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2010-2013 Ettus Research LLC +# Copyright 2010-2014 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 @@ -15,11 +15,11 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # - UHD_INSTALL(FILES bounded_buffer.hpp bounded_buffer.ipp buffer_pool.hpp + chdr.hpp if_addrs.hpp udp_constants.hpp udp_simple.hpp diff --git a/host/include/uhd/transport/chdr.hpp b/host/include/uhd/transport/chdr.hpp new file mode 100644 index 000000000..5e8cd58a9 --- /dev/null +++ b/host/include/uhd/transport/chdr.hpp @@ -0,0 +1,113 @@ +// +// Copyright 2014 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_TRANSPORT_CHDR_HPP +#define INCLUDED_UHD_TRANSPORT_CHDR_HPP + +#include <uhd/transport/vrt_if_packet.hpp> + +namespace uhd{ namespace transport{ namespace vrt{ + +/*! \brief CVITA/CHDR related function + * + * See \ref rtp_chdr for details on the CVITA/CHDR protocol. + * + * All packers take the host format into account. Choose the _le functions + * if the transport uses little endian format (e.g. PCIe) and the _be + * functions if the transport uses big endian format (e.g. Ethernet). + * + * Note 1: All packers assume there to be enough space at the address + * provided by \p packet_buff. See also \ref vrt_pack_contract. + * + * Note 2: All these packers assume the following options without checking them: + * - `if_packet_info.link_type == LINK_TYPE_CHDR` + * - `if_packet_info.has_cid == false` + * - `if_packet_info.has_sid == true` + * - `if_packet_info.has_tsi == false` + * - `if_packet_info.has_tlr == false` + * This relaxes some of \ref vrt_pack_contract, but adds the additional + * constraint that the input data must be CHDR. + * + * In the unpacker, these values will be set accordingly. + */ +namespace chdr{ + + //! The maximum number of 64-bit words in a CVITA header + static const size_t max_if_hdr_words64 = 2; // CHDR + tsf (fractional timestamp) + + /*! + * Pack a CHDR header from metadata (big endian format). + * + * See \ref vrt_pack_contract, but `link_type` is assumed to be + * `LINK_TYPE_CHDR`. + * + * \param packet_buff memory to write the packed vrt header + * \param if_packet_info the if packet info (read/write) + */ + UHD_API void if_hdr_pack_be( + boost::uint32_t *packet_buff, + if_packet_info_t &if_packet_info + ); + + /*! + * Unpack a CHDR header to metadata (big endian format). + * + * See \ref vrt_unpack_contract, but `link_type` is assumed to be + * `LINK_TYPE_CHDR`. + * + * \param packet_buff memory to read the packed vrt header + * \param if_packet_info the if packet info (read/write) + */ + UHD_API void if_hdr_unpack_be( + const boost::uint32_t *packet_buff, + if_packet_info_t &if_packet_info + ); + + /*! + * Pack a CHDR header from metadata (little endian format). + * + * See \ref vrt_pack_contract, but `link_type` is assumed to be + * `LINK_TYPE_CHDR`. + * + * \param packet_buff memory to write the packed vrt header + * \param if_packet_info the if packet info (read/write) + */ + UHD_API void if_hdr_pack_le( + boost::uint32_t *packet_buff, + if_packet_info_t &if_packet_info + ); + + /*! + * Unpack a CHDR header to metadata (little endian format). + * + * See \ref vrt_unpack_contract, but `link_type` is assumed to be + * `LINK_TYPE_CHDR`. + * + * \param packet_buff memory to read the packed vrt header + * \param if_packet_info the if packet info (read/write) + */ + UHD_API void if_hdr_unpack_le( + const boost::uint32_t *packet_buff, + if_packet_info_t &if_packet_info + ); + +} //namespace chdr + +}}} //namespace uhd::transport::vrt + +#endif /* INCLUDED_UHD_TRANSPORT_CHDR_HPP */ + diff --git a/host/include/uhd/transport/nirio/nirio_driver_iface.h b/host/include/uhd/transport/nirio/nirio_driver_iface.h index 10df8e04e..2668c10b9 100644 --- a/host/include/uhd/transport/nirio/nirio_driver_iface.h +++ b/host/include/uhd/transport/nirio/nirio_driver_iface.h @@ -24,10 +24,14 @@ #include <uhd/transport/nirio/status.h> #include <uhd/config.hpp> #if defined(UHD_PLATFORM_WIN32) - #include <Windows.h> - #pragma warning(disable:4201) // nonstandard extension used : nameless struct/union - #include <WinIoCtl.h> - #pragma warning(default:4201) + #include <windows.h> + #ifdef _MSC_VER + #pragma warning(disable:4201) // nonstandard extension used : nameless struct/union + #endif + #include <winioctl.h> + #ifdef _MSC_VER + #pragma warning(default:4201) + #endif #elif defined(UHD_PLATFORM_MACOS) #include <IOKit/IOKitLib.h> #endif @@ -83,7 +87,7 @@ const uint32_t NIRIO_IOCTL_PRE_CLOSE = typedef HANDLE rio_dev_handle_t; #elif defined(UHD_PLATFORM_MACOS) typedef io_connect_t rio_dev_handle_t; -#else //Unsupported platforms +#else typedef int rio_dev_handle_t; #endif static const rio_dev_handle_t INVALID_RIO_HANDLE = ((rio_dev_handle_t)-1); diff --git a/host/include/uhd/transport/nirio/nirio_fifo.h b/host/include/uhd/transport/nirio/nirio_fifo.h index cd471474d..a0cd7149f 100644 --- a/host/include/uhd/transport/nirio/nirio_fifo.h +++ b/host/include/uhd/transport/nirio/nirio_fifo.h @@ -59,8 +59,8 @@ public: inline const std::string& get_name() const { return _name; } inline uint32_t get_channel() const { return _fifo_channel; } - inline uint32_t get_direction() const { return _fifo_direction; } - inline uint32_t get_scalar_type() const { return _datatype_info.scalar_type; } + inline fifo_direction_t get_direction() const { return _fifo_direction; } + inline nirio_scalar_type_t get_scalar_type() const { return _datatype_info.scalar_type; } nirio_status start(); diff --git a/host/include/uhd/transport/nirio/nirio_quirks.h b/host/include/uhd/transport/nirio/nirio_quirks.h index 8e58f80f1..45ef40394 100644 --- a/host/include/uhd/transport/nirio/nirio_quirks.h +++ b/host/include/uhd/transport/nirio/nirio_quirks.h @@ -35,8 +35,8 @@ public: nirio_quirks() : _tx_stream_count(0) { } - UHD_INLINE void register_tx_streams(const uint32_t tx_stream_indices[]) { - for (size_t i = 0; i < sizeof(tx_stream_indices)/sizeof(*tx_stream_indices); i++) { + UHD_INLINE void register_tx_streams(const uint32_t tx_stream_indices[], size_t size) { + for (size_t i = 0; i < size; i++) { _tx_stream_fifo_indices.insert(tx_stream_indices[i]); } } diff --git a/host/include/uhd/transport/tcp_zero_copy.hpp b/host/include/uhd/transport/tcp_zero_copy.hpp index 52e94fab9..ac282d8a2 100644 --- a/host/include/uhd/transport/tcp_zero_copy.hpp +++ b/host/include/uhd/transport/tcp_zero_copy.hpp @@ -1,5 +1,5 @@ // -// Copyright 2010-2014 Ettus Research LLC +// Copyright 2010-2015 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 @@ -32,7 +32,7 @@ namespace uhd{ namespace transport{ */ struct UHD_API tcp_zero_copy : public virtual zero_copy_if { - virtual ~tcp_zero_copy(void) = 0; + virtual ~tcp_zero_copy(void); /*! * Make a new zero copy TCP transport: diff --git a/host/include/uhd/transport/usb_device_handle.hpp b/host/include/uhd/transport/usb_device_handle.hpp index fdea9e2be..bf122f549 100644 --- a/host/include/uhd/transport/usb_device_handle.hpp +++ b/host/include/uhd/transport/usb_device_handle.hpp @@ -41,6 +41,7 @@ namespace uhd { namespace transport { class UHD_API usb_device_handle : boost::noncopyable { public: typedef boost::shared_ptr<usb_device_handle> sptr; + typedef std::pair<boost::uint16_t, boost::uint16_t> vid_pid_pair_t; /*! * Return the device's serial number @@ -83,6 +84,8 @@ public: * \return a vector of USB device handles that match vid and pid */ static std::vector<usb_device_handle::sptr> get_device_list(boost::uint16_t vid, boost::uint16_t pid); + static std::vector<usb_device_handle::sptr> get_device_list(const std::vector<usb_device_handle::vid_pid_pair_t>& vid_pid_pair_list); + }; //namespace usb diff --git a/host/include/uhd/transport/vrt_if_packet.hpp b/host/include/uhd/transport/vrt_if_packet.hpp index 362531567..1e54607c1 100644 --- a/host/include/uhd/transport/vrt_if_packet.hpp +++ b/host/include/uhd/transport/vrt_if_packet.hpp @@ -1,5 +1,5 @@ // -// Copyright 2010-2013 Ettus Research LLC +// Copyright 2010-2014 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 @@ -52,9 +52,18 @@ namespace vrt{ //packet type enum packet_type_t { + // VRT language: PACKET_TYPE_DATA = 0x0, PACKET_TYPE_IF_EXT = 0x1, - PACKET_TYPE_CONTEXT = 0x2 //extension context: has_sid = true + PACKET_TYPE_CONTEXT = 0x2, //extension context: has_sid = true + + // CVITA language: + //PACKET_TYPE_DATA = 0x0, // Data + PACKET_TYPE_FC = 0x1, // Flow control + PACKET_TYPE_ACK = 0x1, // Flow control (ack) + PACKET_TYPE_CMD = 0x2, // Command + PACKET_TYPE_RESP = 0x3, // Command response + PACKET_TYPE_ERROR = 0x3 // Command response: Error (the EOB bit is raised in this case) } packet_type; //size fields @@ -65,18 +74,46 @@ namespace vrt{ //header fields size_t packet_count; + //! Asserted for start- or end-of-burst bool sob, eob; + //! This is asserted for command responses that are errors (CHDR only) + bool error; //optional fields + //! Stream ID (SID). See uhd::sid_t bool has_sid; boost::uint32_t sid; + //! Class ID. bool has_cid; boost::uint64_t cid; + //! Integer timestamp bool has_tsi; boost::uint32_t tsi; + //! Fractional timestamp bool has_tsf; boost::uint64_t tsf; + //! Trailer bool has_tlr; boost::uint32_t tlr; }; /*! * Pack a vrt header from metadata (big endian format). + * + * \section vrt_pack_contract Packing contract + * + * \subsection Requirements: + * - packet_buff points to a valid address space with enough space to write + * the entire buffer, regardless of its length. At the very least, it must + * be able to hold an entire header. + * - `if_packet_info` has the following members set to correct values: + * - `has_*` members all set accordingly + * - For every true `has_*` member, the corresponding variable holds a valid + * value (e.g. if `has_sid` is true, `sid` contains a valid SID) + * - `num_payload_bytes` and `num_payload_words32` are both set to the correct values + * + * \subsection Result: + * - `packet_buff` now points to a valid header that can be sent over the transport + * without further modification + * - The following members on `if_packet_info` are set: + * - `num_header_words32` + * - `num_packet_words32` + * * \param packet_buff memory to write the packed vrt header * \param if_packet_info the if packet info (read/write) */ @@ -87,6 +124,34 @@ namespace vrt{ /*! * Unpack a vrt header to metadata (big endian format). + * + * \section vrt_unpack_contract Unpacking contract + * + * \subsection Requirements + * - `packet_buff` points to a readable address space with a + * CHDR packet, starting at the header. `packet_buff[0]` *must* always + * point to a valid first word of the header. This implies that num_packet_words32 + * must be at least 1. + * - `if_packet_info` has the following members set to correct values: + * - `num_packet_words32`. This means all values `packet_buff[0]` + * through `packet_buff[if_packet_info.num_packet_words32-1]` are + * readable words from this packet. + * - `link_type` + * + * \subsection Result + * - `if_packet_info` now has the following values set to correct values: + * - `packet_type` + * - `num_payload_bytes` + * - `num_payload_words32` + * - `num_header_words32` + * - `has_*` + * - `sob`, `eob`, `error`, `cid`, `sid` (if applicable) + * - `tsf`, `tsi` (if applicable) + * + * \subsection Exceptions + * - If the header is invalid, but the requirements are still met, + * will throw a uhd::value_error. + * * \param packet_buff memory to read the packed vrt header * \param if_packet_info the if packet info (read/write) */ @@ -97,6 +162,9 @@ namespace vrt{ /*! * Pack a vrt header from metadata (little endian format). + * + * See \ref vrt_pack_contract. + * * \param packet_buff memory to write the packed vrt header * \param if_packet_info the if packet info (read/write) */ @@ -107,6 +175,9 @@ namespace vrt{ /*! * Unpack a vrt header to metadata (little endian format). + * + * See \ref vrt_unpack_contract. + * * \param packet_buff memory to read the packed vrt header * \param if_packet_info the if packet info (read/write) */ @@ -124,6 +195,7 @@ namespace vrt{ num_packet_words32(0), packet_count(0), sob(false), eob(false), + error(false), has_sid(false), sid(0), has_cid(false), cid(0), has_tsi(false), tsi(0), diff --git a/host/include/uhd/transport/zero_copy.hpp b/host/include/uhd/transport/zero_copy.hpp index 9ff3042aa..de1b17e1a 100644 --- a/host/include/uhd/transport/zero_copy.hpp +++ b/host/include/uhd/transport/zero_copy.hpp @@ -1,5 +1,5 @@ // -// Copyright 2010-2012 Ettus Research LLC +// Copyright 2010-2012,2015 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 diff --git a/host/include/uhd/types/CMakeLists.txt b/host/include/uhd/types/CMakeLists.txt index 8bb1de381..2a25df35f 100644 --- a/host/include/uhd/types/CMakeLists.txt +++ b/host/include/uhd/types/CMakeLists.txt @@ -17,6 +17,7 @@ UHD_INSTALL(FILES + byte_vector.hpp clock_config.hpp device_addr.hpp dict.ipp @@ -31,11 +32,13 @@ UHD_INSTALL(FILES ref_vector.hpp sensors.hpp serial.hpp + sid.hpp stream_cmd.hpp time_spec.hpp tune_request.hpp tune_result.hpp wb_iface.hpp + filters.hpp DESTINATION ${INCLUDE_DIR}/uhd/types COMPONENT headers ) diff --git a/host/include/uhd/types/byte_vector.hpp b/host/include/uhd/types/byte_vector.hpp new file mode 100644 index 000000000..b7637fb5d --- /dev/null +++ b/host/include/uhd/types/byte_vector.hpp @@ -0,0 +1,48 @@ +// +// Copyright 2015 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_BYTE_VECTOR_HPP +#define INCLUDED_UHD_TYPES_BYTE_VECTOR_HPP + +#include <algorithm> +#include <string> +#include <vector> + +#include <boost/assign.hpp> +#include <boost/cstdint.hpp> + +#include <uhd/config.hpp> + +namespace uhd{ + + //! Byte vector used for I2C data passing and EEPROM parsing. + typedef std::vector<boost::uint8_t> byte_vector_t; + + template<typename RangeSrc, typename RangeDst> UHD_INLINE + void byte_copy(const RangeSrc &src, RangeDst &dst){ + std::copy(boost::begin(src), boost::end(src), boost::begin(dst)); + } + + //! Create a string from a byte vector, terminate when invalid ASCII encountered + UHD_API std::string bytes_to_string(const byte_vector_t &bytes); + + //! Create a byte vector from a string, end at null terminator or max length + UHD_API byte_vector_t string_to_bytes(const std::string &str, size_t max_length); + +} //namespace uhd + +#endif /* INCLUDED_UHD_TYPES_BYTE_VECTOR_HPP */ diff --git a/host/include/uhd/types/dict.hpp b/host/include/uhd/types/dict.hpp index 97fa8f09c..90559ff5f 100644 --- a/host/include/uhd/types/dict.hpp +++ b/host/include/uhd/types/dict.hpp @@ -1,5 +1,5 @@ // -// Copyright 2010-2011 Ettus Research LLC +// Copyright 2010-2011,2015 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 @@ -117,6 +117,23 @@ namespace uhd{ */ Val pop(const Key &key); + /*! Update this dictionary with values from another. + * + * Basically, this copies all the key/value pairs from \p new_dict + * into this dict. When the key is already present in the current + * dict, it either overwrites the current value (if \p fail_on_conflict + * is false) or it throws (if \p fail_on_conflict is true *and* the + * values differ). + * + * With the exception of \p fail_on_conflict, this behaves analogously + * to Python's dict.update() method. + * + * \param new_dict The arguments to copy. + * \param fail_on_conflict If true, throws. + * \throws uhd::value_error + */ + void update(const dict<Key, Val> &new_dict, bool fail_on_conflict=true); + private: typedef std::pair<Key, Val> pair_t; std::list<pair_t> _map; //private container diff --git a/host/include/uhd/types/dict.ipp b/host/include/uhd/types/dict.ipp index 5e9cf97ad..5fd4b536e 100644 --- a/host/include/uhd/types/dict.ipp +++ b/host/include/uhd/types/dict.ipp @@ -135,6 +135,20 @@ namespace uhd{ throw key_not_found<Key, Val>(key); } + template <typename Key, typename Val> + void dict<Key, Val>::update(const dict<Key, Val> &new_dict, bool fail_on_conflict) + { + BOOST_FOREACH(const Key &key, new_dict.keys()) { + if (fail_on_conflict and has_key(key) and get(key) != new_dict[key]) { + throw uhd::value_error(str( + boost::format("Option merge conflict: %s:%s != %s:%s") + % key % get(key) % key % new_dict[key] + )); + } + set(key, new_dict[key]); + } + } + } //namespace uhd #endif /* INCLUDED_UHD_TYPES_DICT_IPP */ diff --git a/host/include/uhd/types/direction.hpp b/host/include/uhd/types/direction.hpp index 0f257de44..59ee9b55f 100644 --- a/host/include/uhd/types/direction.hpp +++ b/host/include/uhd/types/direction.hpp @@ -1,5 +1,5 @@ // -// Copyright 2015 Ettus Research LLC +// Copyright 2014-2015 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 diff --git a/host/include/uhd/types/filters.hpp b/host/include/uhd/types/filters.hpp new file mode 100644 index 000000000..976ae233d --- /dev/null +++ b/host/include/uhd/types/filters.hpp @@ -0,0 +1,286 @@ +// +// Copyright 2015 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_FILTERS_HPP +#define INCLUDED_UHD_TYPES_FILTERS_HPP + +#include <uhd/config.hpp> +#include <uhd/utils/log.hpp> +#include <uhd/utils/msg.hpp> +#include <boost/cstdint.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/scoped_array.hpp> +#include <string> +#include <vector> +#include <iostream> +#include <ostream> +#include <sstream> + +namespace uhd{ + + class UHD_API filter_info_base + { + public: + typedef boost::shared_ptr<filter_info_base> sptr; + enum filter_type + { + ANALOG_LOW_PASS, + ANALOG_BAND_PASS, + DIGITAL_I16, + DIGITAL_FIR_I16 + }; + + filter_info_base( + filter_type type, + bool bypass, + size_t position_index + ): + _type(type), _bypass(bypass), + _position_index(position_index) + { + //NOP + } + + inline virtual bool is_bypassed() + { + return _bypass; + } + + inline filter_type get_type() + { + return _type; + } + + virtual ~filter_info_base() + { + //NOP + } + + virtual std::string to_pp_string(); + + protected: + filter_type _type; + bool _bypass; + size_t _position_index; + + }; + + UHD_API std::ostream& operator<<(std::ostream& os, filter_info_base& f); + + class UHD_API analog_filter_base : public filter_info_base + { + std::string _analog_type; + public: + typedef boost::shared_ptr<analog_filter_base> sptr; + analog_filter_base( + filter_type type, + bool bypass, + size_t position_index, + const std::string& analog_type + ): + filter_info_base(type, bypass, position_index), + _analog_type(analog_type) + { + //NOP + } + + inline const std::string& get_analog_type() + { + return _analog_type; + } + + virtual std::string to_pp_string(); + }; + + class UHD_API analog_filter_lp : public analog_filter_base + { + double _cutoff; + double _rolloff; + + public: + typedef boost::shared_ptr<analog_filter_lp> sptr; + analog_filter_lp( + filter_type type, + bool bypass, + size_t position_index, + const std::string& analog_type, + double cutoff, + double rolloff + ): + analog_filter_base(type, bypass, position_index, analog_type), + _cutoff(cutoff), + _rolloff(rolloff) + { + //NOP + } + + inline double get_cutoff() + { + return _cutoff; + } + + inline double get_rolloff() + { + return _cutoff; + } + + inline void set_cutoff(const double cutoff) + { + _cutoff = cutoff; + } + + virtual std::string to_pp_string(); + }; + + template<typename tap_t> + class UHD_API digital_filter_base : public filter_info_base + { + protected: + double _rate; + boost::uint32_t _interpolation; + boost::uint32_t _decimation; + tap_t _tap_full_scale; + boost::uint32_t _max_num_taps; + std::vector<tap_t> _taps; + + public: + typedef boost::shared_ptr<digital_filter_base> sptr; + digital_filter_base( + filter_type type, + bool bypass, + size_t position_index, + double rate, + size_t interpolation, + size_t decimation, + double tap_full_scale, + size_t max_num_taps, + const std::vector<tap_t>& taps + ): + filter_info_base(type, bypass, position_index), + _rate(rate), + _interpolation(interpolation), + _decimation(decimation), + _tap_full_scale(tap_full_scale), + _max_num_taps(max_num_taps), + _taps(taps) + { + //NOP + } + + inline double get_output_rate() + { + return (_bypass ? _rate : (_rate / _decimation * _interpolation)); + } + + inline double get_input_rate() + { + return _rate; + } + + inline double get_interpolation() + { + return _interpolation; + } + + inline double get_decimation() + { + return _decimation; + } + + inline double get_tap_full_scale() + { + return _tap_full_scale; + } + + inline std::vector<tap_t>& get_taps() + { + return _taps; + } + + virtual std::string to_pp_string() + { + std::ostringstream os; + os<<filter_info_base::to_pp_string()<< + "\t[digital_filter_base]"<<std::endl<< + "\tinput rate: "<<_rate<<std::endl<< + "\tinterpolation: "<<_interpolation<<std::endl<< + "\tdecimation: "<<_decimation<<std::endl<< + "\tfull-scale: "<<_tap_full_scale<<std::endl<< + "\tmax num taps: "<<_max_num_taps<<std::endl<< + "\ttaps: "<<std::endl; + + os<<"\t\t"; + for(size_t i = 0; i < _taps.size(); i++) + { + os<<"(tap "<<i<<": "<<_taps[i]<<")"; + if( ((i%10) == 0) && (i != 0)) + { + os<<std::endl<<"\t\t"; + } + } + os<<std::endl; + return std::string(os.str()); + } + + }; + + template<typename tap_t> + class UHD_API digital_filter_fir : public digital_filter_base<tap_t> + { + public: + typedef boost::shared_ptr<digital_filter_fir<tap_t> > sptr; + + digital_filter_fir( + filter_info_base::filter_type type, + bool bypass, size_t position_index, + double rate, + size_t interpolation, + size_t decimation, + size_t tap_bit_width, + size_t max_num_taps, + const std::vector<tap_t>& taps + ): + digital_filter_base<tap_t>(type, bypass, position_index, rate, interpolation, decimation, tap_bit_width, max_num_taps, taps) + { + //NOP + } + + void set_taps(const std::vector<tap_t>& taps) + { + std::size_t num_taps = taps.size(); + if(num_taps < this->_max_num_taps){ + UHD_MSG(warning) << "digital_filter_fir::set_taps not enough coefficients. Appending zeros"; + std::vector<tap_t> coeffs; + for (size_t i = 0; i < this->_max_num_taps; i++) + { + if(i < num_taps) + { + coeffs.push_back(taps[i]); + } else { + coeffs.push_back(0); + } + } + this->_taps = coeffs; + } else { + this->_taps = taps; + } + } + }; + +} //namespace uhd + +#endif /* INCLUDED_UHD_TYPES_FILTERS_HPP */ diff --git a/host/include/uhd/types/sid.hpp b/host/include/uhd/types/sid.hpp new file mode 100644 index 000000000..95034c7a5 --- /dev/null +++ b/host/include/uhd/types/sid.hpp @@ -0,0 +1,238 @@ +// +// Copyright 2014 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_SID_HPP +#define INCLUDED_UHD_TYPES_SID_HPP + +#include <uhd/config.hpp> +#include <boost/cstdint.hpp> +#include <boost/shared_ptr.hpp> +#include <iostream> + +namespace uhd { + /*! + * \brief Represents a stream ID (SID). + * + * A stream ID (SID) is an identifier for data. + * It is a 32-Bit value which consistst of 16 Bits + * for the source address and 16 Bits for the destination + * address. + * Every address is split into two parts: The _address_, which + * identifies the device used, and the _endpoint_, which identifies + * a specific object inside the given device (e.g., a block). + * *Note:* In the case where there are several crossbars on a single + * device, each crossbar gets its own address. + * Both address and endpoint are 8 bits in length. If a 16-bit address + * is required, we use the combination of the 8-bit address and the 8-bit + * endpoint. + * + * \section sid_str_repr String Representation + * + * The string representation of a SID is of the form + * + * 2.3>0.6 + * + * The '>' symbol shows the direction, so in this case, + * data is flowing from address 2.3 to 0.6. + * + * As a convention, ':' is used instead of '.' when giving the + * SID in hexadecimal numbers, and two characters are used for each + * address part. As an example, the following two SIDs are identical: + * + * 2.3>0.16 (decimal) + * 02:03>00:10 (hexadecimal) + * + * The format is: + * SRC_ADDRESS.SRC_ENDPOINT>DST_ADDRESS.DST_ENDPOINT + * + * + * \section sid_block_ports Block Ports + * + * In the special case where a block on a crossbar is addressed, the + * endpoint is further split up into two parts of four bits each: The + * first four bits specify the port number on the crossbar, whereas the + * lower four bits represent the *block port*. As an example, consider + * the following SID, given in hexadecimal: + * + * 00:10>02:A1 + * + * In this example, assume data is flowing from the host computer to an + * X300. The crossbar address is 02. The endpoint is A1, which means we + * are accessing a block on crossbar port A (the tenth port), and are addressing + * block port 1. + * + */ + class UHD_API sid_t + { + public: + //! Create an unset SID + sid_t(); + //! Create a sid_t object from a 32-Bit SID value + sid_t(boost::uint32_t sid); + //! Create a sid_t object from its four components + sid_t(boost::uint8_t src_addr, boost::uint8_t src_ep, boost::uint8_t dst_addr, boost::uint8_t dst_ep); + //! Convert a string representation of a SID into its numerical representation + sid_t(const std::string &); + + //! Return a decimal string representation of the SID. + std::string to_pp_string() const; + //! Return a hexadecimal string representation of the SID. + std::string to_pp_string_hex() const; + + //! Returns true if this actually holds a valid SID + bool is_set() const { return _set; }; + + // Getters + // + //! Alias for get_sid() + UHD_INLINE boost::uint32_t get() const { return get_sid(); }; + //! Returns a 32-Bit representation of the SID if set, or zero otherwise. + UHD_INLINE boost::uint32_t get_sid() const { return _set ? _sid : 0; }; + //! Return the 16-bit source address of this SID + UHD_INLINE boost::uint32_t get_src() const { + return (_sid >> 16) & 0xFFFF; + } + //! Return the 16-bit destination address of this SID + UHD_INLINE boost::uint32_t get_dst() const { + return _sid & 0xFFFF; + } + //! Return 8-bit address of the source + UHD_INLINE boost::uint32_t get_src_addr() const { + return (get_src() >> 8) & 0xFF; + } + //! Return endpoint of the source + UHD_INLINE boost::uint32_t get_src_endpoint() const { + return get_src() & 0xFF; + } + //! Return crossbar port of the source + UHD_INLINE boost::uint32_t get_src_xbarport() const { + return (get_src_endpoint() >> 4) & 0xF; + } + //! Return block port of the source + UHD_INLINE boost::uint32_t get_src_blockport() const { + return (get_src_endpoint()) & 0xF; + } + //! Return 8-bit address of the destination + UHD_INLINE boost::uint32_t get_dst_addr() const { + return (get_dst() >> 8) & 0xFF; + } + //! Return endpoint of the destination + UHD_INLINE boost::uint32_t get_dst_endpoint() const { + return get_dst() & 0xFF; + } + //! Return crossbar port of the source + UHD_INLINE boost::uint32_t get_dst_xbarport() const { + return (get_dst_endpoint() >> 4) & 0xF; + } + //! Return block port of the source + UHD_INLINE boost::uint32_t get_dst_blockport() const { + return (get_dst_endpoint()) & 0xF; + } + + // Setters + + //! Alias for set_sid() + void set(boost::uint32_t new_sid) { set_sid(new_sid); }; + //! Convert a string representation of a SID into a numerical one + // Throws uhd::value_error if the string is not a valid SID + // representation. + void set_from_str(const std::string &); + void set_sid(boost::uint32_t new_sid); + //! Set the source address of this SID + // (the first 16 Bits) + void set_src(boost::uint32_t new_addr); + //! Set the destination address of this SID + // (the last 16 Bits) + void set_dst(boost::uint32_t new_addr); + void set_src_addr(boost::uint32_t new_addr); + void set_src_endpoint(boost::uint32_t new_addr); + void set_dst_addr(boost::uint32_t new_addr); + void set_dst_endpoint(boost::uint32_t new_addr); + void set_dst_xbarport(boost::uint32_t new_xbarport); + void set_dst_blockport(boost::uint32_t new_blockport); + + // Manipulators + + //! Swaps dst and src address and returns the new SID. + sid_t reversed(); + + //! Swaps dst and src in-place. + void reverse(); + + // Overloaded operators + + sid_t operator = (boost::uint32_t new_sid) { + set_sid(new_sid); + return *this; + } + + sid_t operator = (sid_t &sid) { + set_sid(sid.get_sid()); + return *this; + } + + sid_t operator = (const std::string &sid_str) { + set_from_str(sid_str); + return *this; + } + + bool operator == (const sid_t &sid) const { + return (not _set and not sid.is_set()) or (_sid == sid.get_sid()); + } + + bool operator == (boost::uint32_t sid) const { + return _set and _sid == sid; + } + + bool operator == (const std::string &sid_str) const { + sid_t rhs(sid_str); + return *this == rhs; + } + + // overloaded type casts are tricky, but for now we'll need them + // for backward compatibility. consider them deprecated. + + //! If the SID is not set, always returns zero. + // Use is_set() to check if the return value is valid. + operator boost::uint32_t() const { + return get(); + } + + operator bool() const { + return _set; + } + + private: + boost::uint32_t _sid; + bool _set; + }; + + //! Stream output operator. Honors std::ios::hex. + UHD_INLINE std::ostream& operator<< (std::ostream& out, const sid_t &sid) { + std::ios_base::fmtflags ff = out.flags(); + if (ff & std::ios::hex) { + out << sid.to_pp_string_hex(); + } else { + out << sid.to_pp_string(); + } + return out; + } + +} //namespace uhd + +#endif /* INCLUDED_UHD_TYPES_SID_HPP */ +// vim: sw=4 et: diff --git a/host/include/uhd/usrp/multi_usrp.hpp b/host/include/uhd/usrp/multi_usrp.hpp index 7ac38f84b..8d5dc2e5f 100644 --- a/host/include/uhd/usrp/multi_usrp.hpp +++ b/host/include/uhd/usrp/multi_usrp.hpp @@ -1,5 +1,5 @@ // -// Copyright 2010-2012,2014 Ettus Research LLC +// Copyright 2010-2012,2014-2015 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 @@ -22,6 +22,7 @@ #define UHD_USRP_MULTI_USRP_REF_SOURCES_API #define UHD_USRP_MULTI_USRP_GET_RATES_API #define UHD_USRP_MULTI_USRP_FRONTEND_CAL_API +#define UHD_USRP_MULTI_USRP_FRONTEND_IQ_AUTO_API #define UHD_USRP_MULTI_USRP_COMMAND_TIME_API #define UHD_USRP_MULTI_USRP_BW_RANGE_API #define UHD_USRP_MULTI_USRP_USER_REGS_API @@ -37,6 +38,7 @@ #include <uhd/types/tune_request.hpp> #include <uhd/types/tune_result.hpp> #include <uhd/types/sensors.hpp> +#include <uhd/types/filters.hpp> #include <uhd/usrp/subdev_spec.hpp> #include <uhd/usrp/dboard_iface.hpp> #include <boost/shared_ptr.hpp> @@ -157,6 +159,11 @@ public: * If the specified rate is not available, this method will throw. * On other devices, this method notifies the software of the rate, * but requires the the user has made the necessary hardware change. + * + * If the device has an 'auto clock rate' setting (e.g. B200, see also + * \ref b200_auto_mcr), this will get disabled and the clock rate will be + * fixed to \p rate. + * * \param rate the new master clock rate in Hz * \param mboard the motherboard index 0 to M-1 */ @@ -492,6 +499,34 @@ public: } /*! + * Set the normalized RX gain value. + * + * The normalized gain is a value in [0, 1], where 0 is the + * smallest gain value available, and 1 is the largest, independent + * of the device. In between, gains are linearly interpolated. + * + * Check the individual device manual for notes on the gain range. + * + * Note that it is not possible to specify a gain name for + * this function, it will always set the overall gain. + * + * \param gain the normalized gain value + * \param chan the channel index 0 to N-1 + * \throws A uhd::runtime_error if the gain value is outside [0, 1]. + */ + virtual void set_normalized_rx_gain(double gain, size_t chan = 0) = 0; + + /*! + * Enable or disable the RX AGC module. + * Once this module is enabled manual gain settings will be ignored. + * The AGC will start in a default configuration which should be good for most use cases. + * Device specific configuration parameters can be found in the property tree. + * \param enable Enable or Disable the AGC + * \param chan the channel index 0 to N-1 + */ + virtual void set_rx_agc(bool enable, size_t chan = 0) = 0; + + /*! * 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 @@ -506,6 +541,18 @@ public: } /*! + * Return the normalized RX gain value. + * + * See set_normalized_rx_gain() for a discussion of normalized + * gains. + * + * \param chan the channel index 0 to N-1 + * \returns The normalized gain (in [0, 1]) + * \throws A uhd::runtime_error if the gain value is outside [0, 1]. + */ + virtual double get_normalized_rx_gain(size_t chan = 0) = 0; + + /*! * 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 @@ -617,6 +664,14 @@ public: virtual void set_rx_dc_offset(const std::complex<double> &offset, size_t chan = ALL_CHANS) = 0; /*! + * Enable/disable the automatic IQ imbalance correction. + * + * \param enb true to enable automatic IQ balance correction + * \param chan the channel index 0 to N-1 + */ + virtual void set_rx_iq_balance(const bool enb, size_t chan) = 0; + + /*! * Set the RX frontend IQ imbalance correction. * Use this to adjust the magnitude and phase of I and Q. * @@ -730,6 +785,18 @@ public: } /*! + * Set the normalized TX gain value. + * + * See set_normalized_rx_gain() for a discussion on normalized + * gains. + * + * \param gain the normalized gain value + * \param chan the channel index 0 to N-1 + * \throws A uhd::runtime_error if the gain value is outside [0, 1]. + */ + virtual void set_normalized_tx_gain(double gain, size_t chan = 0) = 0; + + /*! * 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 @@ -744,6 +811,18 @@ public: } /*! + * Return the normalized TX gain value. + * + * See set_normalized_rx_gain() for a discussion of normalized + * gains. + * + * \param chan the channel index 0 to N-1 + * \returns The normalized gain (in [0, 1]) + * \throws A uhd::runtime_error if the gain value is outside [0, 1]. + */ + virtual double get_normalized_tx_gain(size_t chan = 0) = 0; + + /*! * 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 @@ -895,6 +974,38 @@ public: */ virtual boost::uint32_t get_gpio_attr(const std::string &bank, const std::string &attr, const size_t mboard = 0) = 0; + /******************************************************************* + * Filter API methods + ******************************************************************/ + + /*! + * Enumerate the available filters in the signal path. + * \param search_mask + * \parblock + * Select only certain filter names by specifying this search mask. + * + * E.g. if search mask is set to "rx_frontends/A" only filter names including that string will be returned. + * \endparblock + * \return a vector of strings representing the selected filter names. + */ + virtual std::vector<std::string> get_filter_names(const std::string &search_mask = "") = 0; + + /*! + * Return the filter object for the given name. + * \param path the name of the filter as returned from get_filter_names(). + * \return a filter_info_base::sptr. + */ + virtual filter_info_base::sptr get_filter(const std::string &path) = 0; + + /*! + * Write back a filter obtained by get_filter() to the signal path. + * This filter can be a modified version of the originally returned one. + * The information about Rx or Tx is contained in the path parameter. + * \param path the name of the filter as returned from get_filter_names(). + * \param filter the filter_info_base::sptr of the filter object to be written + */ + virtual void set_filter(const std::string &path, filter_info_base::sptr filter) = 0; + }; }} diff --git a/host/include/uhd/usrp_clock/CMakeLists.txt b/host/include/uhd/usrp_clock/CMakeLists.txt index 7cd5aa9d3..a116e4982 100644 --- a/host/include/uhd/usrp_clock/CMakeLists.txt +++ b/host/include/uhd/usrp_clock/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright 2014 Ettus Research LLC +# Copyright 2014-2015 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 @@ -18,6 +18,6 @@ UHD_INSTALL(FILES octoclock_eeprom.hpp multi_usrp_clock.hpp - DESTINATION ${INCLUDE_DIR}/uhd/octoclock + DESTINATION ${INCLUDE_DIR}/uhd/usrp_clock COMPONENT headers ) diff --git a/host/include/uhd/utils/math.hpp b/host/include/uhd/utils/math.hpp index 2937ba802..ef7bfb6b7 100644 --- a/host/include/uhd/utils/math.hpp +++ b/host/include/uhd/utils/math.hpp @@ -18,11 +18,11 @@ #ifndef INCLUDED_UHD_UTILS_MATH_HPP #define INCLUDED_UHD_UTILS_MATH_HPP +#include <cmath> #include <uhd/config.hpp> #include <boost/cstdint.hpp> #include <boost/numeric/conversion/bounds.hpp> - namespace uhd { /*! @@ -237,6 +237,16 @@ namespace fp_compare { == fp_compare::fp_compare_delta<double>(rhs, FREQ_COMPARISON_DELTA_HZ)); } + //! Portable log2() + template <typename float_t> UHD_INLINE + float_t log2(float_t x) + { + // C++11 defines std::log2(), when that's universally supported + // we can switch over. + return std::log(x) / std::log(float_t(2)); + } + + } // namespace math } // namespace uhd diff --git a/host/include/uhd/utils/paths.hpp b/host/include/uhd/utils/paths.hpp index 0dbee3446..cc054b019 100644 --- a/host/include/uhd/utils/paths.hpp +++ b/host/include/uhd/utils/paths.hpp @@ -87,7 +87,7 @@ namespace uhd { * The error string will include the full path to the utility to run. * \return the message suggesting the use of the named utility. */ - UHD_API std::string print_utility_error(std::string name); + UHD_API std::string print_utility_error(const std::string &name, const std::string &args=""); } //namespace uhd #endif /* INCLUDED_UHD_UTILS_PATHS_HPP */ diff --git a/host/include/uhd/utils/soft_register.hpp b/host/include/uhd/utils/soft_register.hpp new file mode 100644 index 000000000..d3537a618 --- /dev/null +++ b/host/include/uhd/utils/soft_register.hpp @@ -0,0 +1,312 @@ +// +// Copyright 2014 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_UTILS_SOFT_REGISTER_HPP +#define INCLUDED_UHD_UTILS_SOFT_REGISTER_HPP + +#include <boost/cstdint.hpp> +#include <boost/noncopyable.hpp> +#include <uhd/types/wb_iface.hpp> +#include <uhd/exception.hpp> +#include <boost/thread/mutex.hpp> +#include <boost/thread/locks.hpp> + +#define UHD_DEFINE_SOFT_REG_FIELD(name, width, shift) \ + static const uhd::soft_reg_field_t name = (((shift & 0xFF) << 8) | (width & 0xFF)) + +namespace uhd { + +/* A register field is defined as a tuple of the mask and the shift. + * It can be used to make read-modify-write operations more convenient + * For efficiency reasons, it is recommended to always use a constant + * of this type because it will get optimized out by the compiler and + * will result in zero memory overhead + */ +typedef boost::uint32_t soft_reg_field_t; + +namespace soft_reg_field { + inline size_t width(const soft_reg_field_t field) { + return (field & 0xFF); + } + + inline size_t shift(const soft_reg_field_t field) { + return ((field >> 8) & 0xFF); + } + + template<typename data_t> + inline size_t mask(const soft_reg_field_t field) { + return ((static_cast<data_t>(1)<<width(field))-1)<<shift(field); + } +} + +/*! + * Soft register object that holds offset, soft-copy and the control iface. + * Methods give convenient field-level access to soft-copy and the ability + * to do read-modify-write operations. + */ +template<typename reg_data_t, bool readable, bool writeable> +class UHD_API soft_register_t : public boost::noncopyable { +public: + typedef boost::shared_ptr< soft_register_t<reg_data_t, readable, writeable> > sptr; + + /*! + * Generic constructor for all soft_register types + */ + soft_register_t(wb_iface::wb_addr_type wr_addr, wb_iface::wb_addr_type rd_addr): + _iface(NULL), _wr_addr(wr_addr), _rd_addr(rd_addr), _soft_copy(0) + {} + + /*! + * Constructor for read-only, write-only registers and read-write registers + * with rd_addr == wr_addr + */ + soft_register_t(wb_iface::wb_addr_type addr): + _iface(NULL), _wr_addr(addr), _rd_addr(addr), _soft_copy(0) + {} + + /*! + * Initialize the register when the underlying bus is usable. + * Can be optionally synced with hardware. + * NOTE: Memory management of the iface is up to the caller + */ + inline void initialize(wb_iface& iface, bool sync = false) + { + _iface = &iface; + + //Synchronize with hardware. For RW register, flush THEN refresh. + if (sync && writeable) flush(); + if (sync && readable) refresh(); + } + + /*! + * Update specified field in the soft-copy with the arg value. + * Performs a read-modify-write operation so all other field are preserved. + * NOTE: This does not write the value to hardware. + */ + inline void set(const soft_reg_field_t field, const reg_data_t value) + { + _soft_copy = (_soft_copy & ~soft_reg_field::mask<reg_data_t>(field)) | + ((value << soft_reg_field::shift(field)) & soft_reg_field::mask<reg_data_t>(field)); + } + + /*! + * Get the value of the specified field from the soft-copy. + * NOTE: This does not read anything from hardware. + */ + inline reg_data_t get(const soft_reg_field_t field) + { + return (_soft_copy & soft_reg_field::mask<reg_data_t>(field)) >> soft_reg_field::shift(field); + } + + /*! + * Write the contents of the soft-copy to hardware. + */ + inline void flush() + { + if (writeable && _iface) { + if (sizeof(reg_data_t) <= 2) { + _iface->poke16(_wr_addr, static_cast<boost::uint16_t>(_soft_copy)); + } else if (sizeof(reg_data_t) <= 4) { + _iface->poke32(_wr_addr, static_cast<boost::uint32_t>(_soft_copy)); + } else if (sizeof(reg_data_t) <= 8) { + _iface->poke64(_wr_addr, static_cast<boost::uint64_t>(_soft_copy)); + } else { + throw uhd::not_implemented_error("soft_register only supports up to 64 bits."); + } + } else { + throw uhd::not_implemented_error("soft_register is not writable."); + } + } + + /*! + * Read the contents of the register from hardware and update the soft copy. + */ + inline void refresh() + { + if (readable && _iface) { + if (sizeof(reg_data_t) <= 2) { + _soft_copy = static_cast<reg_data_t>(_iface->peek16(_rd_addr)); + } else if (sizeof(reg_data_t) <= 4) { + _soft_copy = static_cast<reg_data_t>(_iface->peek32(_rd_addr)); + } else if (sizeof(reg_data_t) <= 8) { + _soft_copy = static_cast<reg_data_t>(_iface->peek64(_rd_addr)); + } else { + throw uhd::not_implemented_error("soft_register only supports up to 64 bits."); + } + } else { + throw uhd::not_implemented_error("soft_register is not readable."); + } + } + + /*! + * Shortcut for a set and a flush. + */ + inline void write(const soft_reg_field_t field, const reg_data_t value) + { + set(field, value); + flush(); + } + + /*! + * Shortcut for refresh and get + */ + inline reg_data_t read(const soft_reg_field_t field) + { + refresh(); + return get(field); + } + +private: + wb_iface* _iface; + const wb_iface::wb_addr_type _wr_addr; + const wb_iface::wb_addr_type _rd_addr; + reg_data_t _soft_copy; +}; + +/*! + * A synchronized soft register object. + * All operations in the synchronized register are serialized. + */ +template<typename reg_data_t, bool readable, bool writeable> +class UHD_API soft_register_sync_t : public soft_register_t<reg_data_t, readable, writeable> { +public: + typedef boost::shared_ptr< soft_register_sync_t<reg_data_t, readable, writeable> > sptr; + + soft_register_sync_t(wb_iface::wb_addr_type wr_addr, wb_iface::wb_addr_type rd_addr): + soft_register_t<reg_data_t, readable, writeable>(wr_addr, rd_addr), _mutex() + {} + + soft_register_sync_t(wb_iface::wb_addr_type addr): + soft_register_t<reg_data_t, readable, writeable>(addr), _mutex() + {} + + inline void initialize(wb_iface& iface, bool sync = false) + { + boost::lock_guard<boost::mutex> lock(_mutex); + soft_register_t<reg_data_t, readable, writeable>::initialize(iface, sync); + } + + inline void set(const soft_reg_field_t field, const reg_data_t value) + { + boost::lock_guard<boost::mutex> lock(_mutex); + soft_register_t<reg_data_t, readable, writeable>::set(field, value); + } + + inline reg_data_t get(const soft_reg_field_t field) + { + boost::lock_guard<boost::mutex> lock(_mutex); + return soft_register_t<reg_data_t, readable, writeable>::get(field); + } + + inline void flush() + { + boost::lock_guard<boost::mutex> lock(_mutex); + soft_register_t<reg_data_t, readable, writeable>::flush(); + } + + inline void refresh() + { + boost::lock_guard<boost::mutex> lock(_mutex); + soft_register_t<reg_data_t, readable, writeable>::refresh(); + } + + inline void write(const soft_reg_field_t field, const reg_data_t value) + { + boost::lock_guard<boost::mutex> lock(_mutex); + soft_register_t<reg_data_t, readable, writeable>::write(field, value); + } + + inline reg_data_t read(const soft_reg_field_t field) + { + boost::lock_guard<boost::mutex> lock(_mutex); + return soft_register_t<reg_data_t, readable, writeable>::read(field); + } + +private: + boost::mutex _mutex; +}; + +/* + * Register Shortcut Formats: + * - soft_reg<bits>_<mode>_t: Soft register object with an unsynchronized soft-copy. + * Thread unsafe but lightweight. Mostly const propagated. + * - soft_reg<bits>_<mode>_sync_t: Soft register object with a synchronized soft-copy. + * Thread safe but with memory/speed overhead. + * where: + * - <bits> = {16, 32 or 64} + * - <mode> = {wo(write-only), rw(read-write) or ro(read-only)} + * + */ + +//16-bit shortcuts +typedef soft_register_t<boost::uint16_t, false, true> soft_reg16_wo_t; +typedef soft_register_t<boost::uint16_t, true, false> soft_reg16_ro_t; +typedef soft_register_t<boost::uint16_t, true, true> soft_reg16_rw_t; +typedef soft_register_sync_t<boost::uint16_t, false, true> soft_reg16_wo_sync_t; +typedef soft_register_sync_t<boost::uint16_t, true, false> soft_reg16_ro_sync_t; +typedef soft_register_sync_t<boost::uint16_t, true, true> soft_reg16_rw_sync_t; +//32-bit shortcuts +typedef soft_register_t<boost::uint32_t, false, true> soft_reg32_wo_t; +typedef soft_register_t<boost::uint32_t, true, false> soft_reg32_ro_t; +typedef soft_register_t<boost::uint32_t, true, true> soft_reg32_rw_t; +typedef soft_register_sync_t<boost::uint32_t, false, true> soft_reg32_wo_sync_t; +typedef soft_register_sync_t<boost::uint32_t, true, false> soft_reg32_ro_sync_t; +typedef soft_register_sync_t<boost::uint32_t, true, true> soft_reg32_rw_sync_t; +//64-bit shortcuts +typedef soft_register_t<boost::uint64_t, false, true> soft_reg64_wo_t; +typedef soft_register_t<boost::uint64_t, true, false> soft_reg64_ro_t; +typedef soft_register_t<boost::uint64_t, true, true> soft_reg64_rw_t; +typedef soft_register_sync_t<boost::uint64_t, false, true> soft_reg64_wo_sync_t; +typedef soft_register_sync_t<boost::uint64_t, true, false> soft_reg64_ro_sync_t; +typedef soft_register_sync_t<boost::uint64_t, true, true> soft_reg64_rw_sync_t; + + +/* + * Usage example + * + //===Define bit width, RW mode, and synchronization using base class=== + class example_reg_t : public soft_reg32_wo_sync_t (or soft_reg32_wo_t) { + public: + //===Define all the fields=== + UHD_DEFINE_SOFT_REG_FIELD(FIELD0, 1, 0); //[0] + UHD_DEFINE_SOFT_REG_FIELD(FIELD1, 15, 1); //[15:1] + UHD_DEFINE_SOFT_REG_FIELD(FIELD2, 16, 16); //[31:16] + + example_reg_t(): //ctor with no args + soft_reg32_wo_t(SR_CORE_EXAMPLE_REG_OFFSET)) //===Bind to offset=== + { + //===Set Initial values=== + set(FIELD0, 0); + set(FIELD1, 1); + set(FIELD2, 0xFFFF); + } + }; //===Full register definition encapsulated in one class=== + + void main() { + example_reg_t reg_obj; + reg_obj.initialize(iface); + reg_obj.write(example_reg_t::FIELD2, 0x1234); + + example_reg_t::sptr reg_sptr = boost::make_shared<example_reg_t>(); + reg_obj->initialize(iface); + reg_obj->write(example_reg_t::FIELD2, 0x1234); + } +*/ + +} //namespace uhd + +#endif /* INCLUDED_UHD_UTILS_SOFT_REGISTER_HPP */ |