diff options
-rw-r--r-- | host/include/uhd/types/CMakeLists.txt | 1 | ||||
-rw-r--r-- | host/include/uhd/types/sid.hpp | 238 | ||||
-rw-r--r-- | host/lib/types/CMakeLists.txt | 1 | ||||
-rw-r--r-- | host/lib/types/sid.cpp | 153 | ||||
-rw-r--r-- | host/tests/CMakeLists.txt | 1 | ||||
-rw-r--r-- | host/tests/sid_t_test.cpp | 158 |
6 files changed, 552 insertions, 0 deletions
diff --git a/host/include/uhd/types/CMakeLists.txt b/host/include/uhd/types/CMakeLists.txt index 334f1b41b..66b8662a1 100644 --- a/host/include/uhd/types/CMakeLists.txt +++ b/host/include/uhd/types/CMakeLists.txt @@ -29,6 +29,7 @@ UHD_INSTALL(FILES ref_vector.hpp sensors.hpp serial.hpp + sid.hpp stream_cmd.hpp time_spec.hpp tune_request.hpp diff --git a/host/include/uhd/types/sid.hpp b/host/include/uhd/types/sid.hpp new file mode 100644 index 000000000..12f98ff97 --- /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 + * + * 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 + * + * 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/lib/types/CMakeLists.txt b/host/lib/types/CMakeLists.txt index f19043c1e..853da3fe2 100644 --- a/host/lib/types/CMakeLists.txt +++ b/host/lib/types/CMakeLists.txt @@ -86,6 +86,7 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/ranges.cpp ${CMAKE_CURRENT_SOURCE_DIR}/sensors.cpp ${CMAKE_CURRENT_SOURCE_DIR}/serial.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/sid.cpp ${CMAKE_CURRENT_SOURCE_DIR}/time_spec.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tune.cpp ${CMAKE_CURRENT_SOURCE_DIR}/types.cpp diff --git a/host/lib/types/sid.cpp b/host/lib/types/sid.cpp new file mode 100644 index 000000000..2fc3781cf --- /dev/null +++ b/host/lib/types/sid.cpp @@ -0,0 +1,153 @@ +// +// 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/>. +// + +#include <boost/format.hpp> +#include <boost/regex.hpp> +#include <boost/lexical_cast.hpp> +#include <uhd/exception.hpp> +#include <uhd/types/sid.hpp> +#include <uhd/utils/cast.hpp> + +using namespace uhd; + +sid_t::sid_t() + : _sid(0x0000), _set(false) +{ +} + +sid_t::sid_t(boost::uint32_t sid) + : _sid(sid), _set(true) +{ +} + +sid_t::sid_t(boost::uint8_t src_addr, boost::uint8_t src_ep, boost::uint8_t dst_addr, boost::uint8_t dst_ep) + : _sid(0x0000), _set(true) +{ + set_src_addr(src_addr); + set_src_endpoint(src_ep); + set_dst_addr(dst_addr); + set_dst_endpoint(dst_ep); +} + +sid_t::sid_t(const std::string &sid_str) + : _sid(0x0000), _set(false) +{ + set_from_str(sid_str); +} + +std::string sid_t::to_pp_string() const +{ + if (not _set) { + return "x.x>x.x"; + } + return str(boost::format("%d.%d>%d.%d") + % get_src_addr() + % get_src_endpoint() + % get_dst_addr() + % get_dst_endpoint() + ); +} + +std::string sid_t::to_pp_string_hex() const +{ + if (not _set) { + return "xx:xx>xx:xx"; + } + return str(boost::format("%02x:%02x>%02x:%02x") + % get_src_addr() + % get_src_endpoint() + % get_dst_addr() + % get_dst_endpoint() + ); +} + + +void sid_t::set_sid(boost::uint32_t new_sid) +{ + _set = true; + _sid = new_sid; +} + +void sid_t::set_from_str(const std::string &sid_str) +{ + const std::string dec_regex = "(\\d{1,3})\\.(\\d{1,3})[.:/><](\\d{1,3})\\.(\\d{1,3})"; + const std::string hex_regex = "([[:xdigit:]]{2}):([[:xdigit:]]{2})[.:/><]([[:xdigit:]]{2}):([[:xdigit:]]{2})"; + + boost::cmatch matches; + if (boost::regex_match(sid_str.c_str(), matches, boost::regex(dec_regex))) { + set_src_addr(boost::lexical_cast<size_t>(matches[1])); + set_src_endpoint(boost::lexical_cast<size_t>(matches[2])); + set_dst_addr(boost::lexical_cast<size_t>(matches[3])); + set_dst_endpoint(boost::lexical_cast<size_t>(matches[4])); + return; + } + + if (boost::regex_match(sid_str.c_str(), matches, boost::regex(hex_regex))) { + set_src_addr(uhd::cast::hexstr_cast<size_t>(matches[1])); + set_src_endpoint(uhd::cast::hexstr_cast<size_t>(matches[2])); + set_dst_addr(uhd::cast::hexstr_cast<size_t>(matches[3])); + set_dst_endpoint(uhd::cast::hexstr_cast<size_t>(matches[4])); + return; + } + + throw uhd::value_error(str(boost::format("Invalid SID representation: %s") % sid_str)); +} + +void sid_t::set_src(boost::uint32_t new_addr) { + set_sid((_sid & 0x0000FFFF) | ((new_addr & 0xFFFF) << 16)); +} + +void sid_t::set_dst(boost::uint32_t new_addr) { + set_sid((_sid & 0xFFFF0000) | (new_addr & 0xFFFF)); +} + +void sid_t::set_src_addr(boost::uint32_t new_addr) { + set_sid((_sid & 0x00FFFFFF) | ((new_addr & 0xFF) << 24)); +} + +void sid_t::set_src_endpoint(boost::uint32_t new_addr) { + set_sid((_sid & 0xFF00FFFF) | ((new_addr & 0xFF) << 16)); +} + +void sid_t::set_dst_addr(boost::uint32_t new_addr) { + set_sid((_sid & 0xFFFF00FF) | ((new_addr & 0xFF) << 8)); +} + +void sid_t::set_dst_endpoint(boost::uint32_t new_addr) { + set_sid((_sid & 0xFFFFFF00) | ((new_addr & 0xFF) << 0)); +} + +void sid_t::set_dst_xbarport(boost::uint32_t new_xbarport) +{ + set_sid((_sid & 0xFFFFFF0F) | ((new_xbarport & 0xF) << 4)); +} + +void sid_t::set_dst_blockport(boost::uint32_t new_blockport) +{ + set_sid((_sid & 0xFFFFFFF0) | ((new_blockport & 0xF) << 0)); +} + +sid_t sid_t::reversed() +{ + return sid_t((get_dst() << 16) | get_src()); +} + +void sid_t::reverse() +{ + set_sid((get_dst() << 16) | get_src()); +} + diff --git a/host/tests/CMakeLists.txt b/host/tests/CMakeLists.txt index 62544b69b..ea0b30cb8 100644 --- a/host/tests/CMakeLists.txt +++ b/host/tests/CMakeLists.txt @@ -37,6 +37,7 @@ SET(test_sources msg_test.cpp property_test.cpp ranges_test.cpp + sid_t_test.cpp sph_recv_test.cpp sph_send_test.cpp subdev_spec_test.cpp diff --git a/host/tests/sid_t_test.cpp b/host/tests/sid_t_test.cpp new file mode 100644 index 000000000..71ab2c213 --- /dev/null +++ b/host/tests/sid_t_test.cpp @@ -0,0 +1,158 @@ +// +// 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/>. +// + +#include <iostream> +#include <sstream> +#include <boost/test/unit_test.hpp> +#include <uhd/types/sid.hpp> +#include <uhd/exception.hpp> + +using uhd::sid_t; + +BOOST_AUTO_TEST_CASE(test_sid_t) { + boost::uint32_t sid_value = 0x01020310; + sid_t sid(sid_value); + + BOOST_CHECK_EQUAL(sid.is_set(), true); + BOOST_CHECK_EQUAL(sid.to_pp_string(), "1.2>3.16"); + BOOST_CHECK_EQUAL(sid.to_pp_string_hex(), "01:02>03:10"); + BOOST_CHECK_EQUAL(sid.get_src(), 0x0102); + BOOST_CHECK_EQUAL(sid.get_dst(), 0x0310); + BOOST_CHECK_EQUAL(sid.get_src_addr(), 0x01); + BOOST_CHECK_EQUAL(sid.get_src_endpoint(), 0x02); + BOOST_CHECK_EQUAL(sid.get_dst_addr(), 0x03); + BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), 0x10); + BOOST_CHECK_EQUAL(sid == sid, true); + BOOST_CHECK_EQUAL(sid == sid_value, true); + + boost::uint32_t check_sid_val = (boost::uint32_t) sid; + BOOST_CHECK_EQUAL(check_sid_val, sid_value); + + std::stringstream ss_dec; + ss_dec << sid; + BOOST_CHECK_EQUAL(ss_dec.str(), "1.2>3.16"); + + std::stringstream ss_hex; + ss_hex << std::hex << sid; + BOOST_CHECK_EQUAL(ss_hex.str(), "01:02>03:10"); + + sid_t empty_sid; + BOOST_CHECK_EQUAL(empty_sid.is_set(), false); + BOOST_CHECK_EQUAL(empty_sid.to_pp_string(), "x.x>x.x"); + BOOST_CHECK_EQUAL(empty_sid.to_pp_string_hex(), "xx:xx>xx:xx"); + BOOST_CHECK_EQUAL(empty_sid == sid, false); + BOOST_CHECK_EQUAL(empty_sid == sid_value, false); + BOOST_CHECK_EQUAL((bool) empty_sid, false); + + empty_sid = sid_value; // No longer empty + BOOST_CHECK_EQUAL(empty_sid.is_set(), true); + BOOST_CHECK_EQUAL(empty_sid == sid, true); +} + +BOOST_AUTO_TEST_CASE(test_sid_t_set) { + boost::uint32_t sid_value = 0x0; + sid_t sid(sid_value); + + sid.set(0x01020304); + BOOST_CHECK_EQUAL(sid.get(), 0x01020304); + BOOST_CHECK_EQUAL(sid.get_src_addr(), 0x01); + BOOST_CHECK_EQUAL(sid.get_src_endpoint(), 0x02); + BOOST_CHECK_EQUAL(sid.get_dst_addr(), 0x03); + BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), 0x04); + BOOST_CHECK_EQUAL(sid.get_dst_xbarport(), 0x0); + BOOST_CHECK_EQUAL(sid.get_dst_blockport(), 0x4); + + sid.set_src_addr(0x0a); + BOOST_CHECK_EQUAL(sid.get(), 0x0a020304); + BOOST_CHECK_EQUAL(sid.get_src_addr(), 0x0a); + BOOST_CHECK_EQUAL(sid.get_src_endpoint(), 0x02); + BOOST_CHECK_EQUAL(sid.get_dst_addr(), 0x03); + BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), 0x04); + + sid.set_src_endpoint(0x0b); + BOOST_CHECK_EQUAL(sid.get(), 0x0a0b0304); + BOOST_CHECK_EQUAL(sid.get_src_addr(), 0x0a); + BOOST_CHECK_EQUAL(sid.get_src_endpoint(), 0x0b); + BOOST_CHECK_EQUAL(sid.get_dst_addr(), 0x03); + BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), 0x04); + + sid.set_dst_addr(0x0c); + BOOST_CHECK_EQUAL(sid.get(), 0x0a0b0c04); + BOOST_CHECK_EQUAL(sid.get_src_addr(), 0x0a); + BOOST_CHECK_EQUAL(sid.get_src_endpoint(), 0x0b); + BOOST_CHECK_EQUAL(sid.get_dst_addr(), 0x0c); + BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), 0x04); + + sid.set_dst_endpoint(0x0d); + BOOST_CHECK_EQUAL(sid.get(), 0x0a0b0c0d); + BOOST_CHECK_EQUAL(sid.get_src_addr(), 0x0a); + BOOST_CHECK_EQUAL(sid.get_src_endpoint(), 0x0b); + BOOST_CHECK_EQUAL(sid.get_dst_addr(), 0x0c); + BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), 0x0d); + + sid.set_dst_xbarport(0xb); + BOOST_CHECK_EQUAL(sid.get(), 0x0a0b0cbd); + BOOST_CHECK_EQUAL(sid.get_src_addr(), 0x0a); + BOOST_CHECK_EQUAL(sid.get_src_endpoint(), 0x0b); + BOOST_CHECK_EQUAL(sid.get_dst_addr(), 0x0c); + BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), 0xbd); + + sid.set_dst_blockport(0xc); + BOOST_CHECK_EQUAL(sid.get(), 0x0a0b0cbc); + BOOST_CHECK_EQUAL(sid.get_src_addr(), 0x0a); + BOOST_CHECK_EQUAL(sid.get_src_endpoint(), 0x0b); + BOOST_CHECK_EQUAL(sid.get_dst_addr(), 0x0c); + BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), 0xbc); + + sid_t flipped_sid = sid.reversed(); + BOOST_CHECK_EQUAL(flipped_sid.get(), 0x0cbc0a0b); + + // In-place + sid.reverse(); + BOOST_CHECK_EQUAL(sid.get(), 0x0cbc0a0b); +} + +BOOST_AUTO_TEST_CASE(test_sid_t_from_str) { + sid_t sid("1.2>3.4"); + BOOST_CHECK_EQUAL(sid.get_src_addr(), 1); + BOOST_CHECK_EQUAL(sid.get_src_endpoint(), 2); + BOOST_CHECK_EQUAL(sid.get_dst_addr(), 3); + BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), 4); + + sid = "01:02>03:10"; + BOOST_CHECK_EQUAL(sid.get_src_addr(), 1); + BOOST_CHECK_EQUAL(sid.get_src_endpoint(), 2); + BOOST_CHECK_EQUAL(sid.get_dst_addr(), 3); + BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), 16); + + sid = "01:06/03:10"; + BOOST_CHECK_EQUAL(sid.get_src_addr(), 1); + BOOST_CHECK_EQUAL(sid.get_src_endpoint(), 6); + BOOST_CHECK_EQUAL(sid.get_dst_addr(), 3); + BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), 16); + + sid = "01:02:04:10"; + BOOST_CHECK_EQUAL(sid.get_src_addr(), 1); + BOOST_CHECK_EQUAL(sid.get_src_endpoint(), 2); + BOOST_CHECK_EQUAL(sid.get_dst_addr(), 4); + BOOST_CHECK_EQUAL(sid.get_dst_endpoint(), 16); + + BOOST_REQUIRE_THROW(sid_t fail_sid("foobar"), uhd::value_error); + BOOST_REQUIRE_THROW(sid_t fail_sid("01:02:03:4"), uhd::value_error); + BOOST_REQUIRE_THROW(sid_t fail_sid("01:02:03:004"), uhd::value_error); + BOOST_REQUIRE_THROW(sid_t fail_sid("1.2.3.0004"), uhd::value_error); +} |