diff options
Diffstat (limited to 'host')
85 files changed, 3599 insertions, 1037 deletions
| diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index 7f7d58658..90fe2b56b 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -269,8 +269,8 @@ UHD_INSTALL(FILES  #{{{IMG_SECTION  # This section is written automatically by /images/create_imgs_package.py  # Any manual changes in here will be overwritten. -SET(UHD_IMAGES_MD5SUM "2ff397927220f591f377a04c9e9e8b7e") -SET(UHD_IMAGES_DOWNLOAD_SRC "uhd-images_003.009.001-release.zip") +SET(UHD_IMAGES_MD5SUM "0529c77990ddae70fd8edba5afdf04b0") +SET(UHD_IMAGES_DOWNLOAD_SRC "uhd-images_003.010.git-53-gb48fe5bb.zip")  #}}}  ######################################################################## diff --git a/host/cmake/Modules/UHDVersion.cmake b/host/cmake/Modules/UHDVersion.cmake index 93687a334..696817a96 100644 --- a/host/cmake/Modules/UHDVersion.cmake +++ b/host/cmake/Modules/UHDVersion.cmake @@ -27,9 +27,9 @@ FIND_PACKAGE(Git QUIET)  #  - set UHD_VERSION_DEVEL to true for master and development branches  ########################################################################  SET(UHD_VERSION_MAJOR 003) -SET(UHD_VERSION_MINOR 009) -SET(UHD_VERSION_PATCH 001) -SET(UHD_VERSION_DEVEL FALSE) +SET(UHD_VERSION_MINOR 010) +SET(UHD_VERSION_PATCH git) +SET(UHD_VERSION_DEVEL TRUE)  ########################################################################  # Set up trimmed version numbers for DLL resource files and packages diff --git a/host/cmake/msvc/inttypes.h b/host/cmake/msvc/inttypes.h deleted file mode 100644 index 1c2baa82e..000000000 --- a/host/cmake/msvc/inttypes.h +++ /dev/null @@ -1,301 +0,0 @@ -// ISO C9x  compliant inttypes.h for Microsoft Visual Studio -// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124  -//  -//  Copyright (c) 2006 Alexander Chemeris -//  -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -//  -//   1. Redistributions of source code must retain the above copyright notice, -//      this list of conditions and the following disclaimer. -//  -//   2. Redistributions in binary form must reproduce the above copyright -//      notice, this list of conditions and the following disclaimer in the -//      documentation and/or other materials provided with the distribution. -//  -//   3. The name of the author may be used to endorse or promote products -//      derived from this software without specific prior written permission. -//  -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -//  -/////////////////////////////////////////////////////////////////////////////// - -#ifndef _MSC_VER // [ -#error "Use this header only with Microsoft Visual C++ compilers!" -#endif // _MSC_VER ] - -#ifndef _MSC_INTTYPES_H_ // [ -#define _MSC_INTTYPES_H_ - -#if _MSC_VER > 1000 -#pragma once -#endif - -#include <stdint.h> - -// 7.8 Format conversion of integer types - -typedef struct { -   intmax_t quot; -   intmax_t rem; -} imaxdiv_t; - -// 7.8.1 Macros for format specifiers - -// The fprintf macros for signed integers are: -#define PRId8       "d" -#define PRIi8       "i" -#define PRIdLEAST8  "d" -#define PRIiLEAST8  "i" -#define PRIdFAST8   "d" -#define PRIiFAST8   "i" - -#define PRId16       "hd" -#define PRIi16       "hi" -#define PRIdLEAST16  "hd" -#define PRIiLEAST16  "hi" -#define PRIdFAST16   "hd" -#define PRIiFAST16   "hi" - -#define PRId32       "I32d" -#define PRIi32       "I32i" -#define PRIdLEAST32  "I32d" -#define PRIiLEAST32  "I32i" -#define PRIdFAST32   "I32d" -#define PRIiFAST32   "I32i" - -#define PRId64       "I64d" -#define PRIi64       "I64i" -#define PRIdLEAST64  "I64d" -#define PRIiLEAST64  "I64i" -#define PRIdFAST64   "I64d" -#define PRIiFAST64   "I64i" - -#define PRIdMAX     "I64d" -#define PRIiMAX     "I64i" - -#define PRIdPTR     "Id" -#define PRIiPTR     "Ii" - -// The fprintf macros for unsigned integers are: -#define PRIo8       "o" -#define PRIu8       "u" -#define PRIx8       "x" -#define PRIX8       "X" -#define PRIoLEAST8  "o" -#define PRIuLEAST8  "u" -#define PRIxLEAST8  "x" -#define PRIXLEAST8  "X" -#define PRIoFAST8   "o" -#define PRIuFAST8   "u" -#define PRIxFAST8   "x" -#define PRIXFAST8   "X" - -#define PRIo16       "ho" -#define PRIu16       "hu" -#define PRIx16       "hx" -#define PRIX16       "hX" -#define PRIoLEAST16  "ho" -#define PRIuLEAST16  "hu" -#define PRIxLEAST16  "hx" -#define PRIXLEAST16  "hX" -#define PRIoFAST16   "ho" -#define PRIuFAST16   "hu" -#define PRIxFAST16   "hx" -#define PRIXFAST16   "hX" - -#define PRIo32       "I32o" -#define PRIu32       "I32u" -#define PRIx32       "I32x" -#define PRIX32       "I32X" -#define PRIoLEAST32  "I32o" -#define PRIuLEAST32  "I32u" -#define PRIxLEAST32  "I32x" -#define PRIXLEAST32  "I32X" -#define PRIoFAST32   "I32o" -#define PRIuFAST32   "I32u" -#define PRIxFAST32   "I32x" -#define PRIXFAST32   "I32X" - -#define PRIo64       "I64o" -#define PRIu64       "I64u" -#define PRIx64       "I64x" -#define PRIX64       "I64X" -#define PRIoLEAST64  "I64o" -#define PRIuLEAST64  "I64u" -#define PRIxLEAST64  "I64x" -#define PRIXLEAST64  "I64X" -#define PRIoFAST64   "I64o" -#define PRIuFAST64   "I64u" -#define PRIxFAST64   "I64x" -#define PRIXFAST64   "I64X" - -#define PRIoMAX     "I64o" -#define PRIuMAX     "I64u" -#define PRIxMAX     "I64x" -#define PRIXMAX     "I64X" - -#define PRIoPTR     "Io" -#define PRIuPTR     "Iu" -#define PRIxPTR     "Ix" -#define PRIXPTR     "IX" - -// The fscanf macros for signed integers are: -#define SCNd8       "d" -#define SCNi8       "i" -#define SCNdLEAST8  "d" -#define SCNiLEAST8  "i" -#define SCNdFAST8   "d" -#define SCNiFAST8   "i" - -#define SCNd16       "hd" -#define SCNi16       "hi" -#define SCNdLEAST16  "hd" -#define SCNiLEAST16  "hi" -#define SCNdFAST16   "hd" -#define SCNiFAST16   "hi" - -#define SCNd32       "ld" -#define SCNi32       "li" -#define SCNdLEAST32  "ld" -#define SCNiLEAST32  "li" -#define SCNdFAST32   "ld" -#define SCNiFAST32   "li" - -#define SCNd64       "I64d" -#define SCNi64       "I64i" -#define SCNdLEAST64  "I64d" -#define SCNiLEAST64  "I64i" -#define SCNdFAST64   "I64d" -#define SCNiFAST64   "I64i" - -#define SCNdMAX     "I64d" -#define SCNiMAX     "I64i" - -#ifdef _WIN64 // [ -#  define SCNdPTR     "I64d" -#  define SCNiPTR     "I64i" -#else  // _WIN64 ][ -#  define SCNdPTR     "ld" -#  define SCNiPTR     "li" -#endif  // _WIN64 ] - -// The fscanf macros for unsigned integers are: -#define SCNo8       "o" -#define SCNu8       "u" -#define SCNx8       "x" -#define SCNX8       "X" -#define SCNoLEAST8  "o" -#define SCNuLEAST8  "u" -#define SCNxLEAST8  "x" -#define SCNXLEAST8  "X" -#define SCNoFAST8   "o" -#define SCNuFAST8   "u" -#define SCNxFAST8   "x" -#define SCNXFAST8   "X" - -#define SCNo16       "ho" -#define SCNu16       "hu" -#define SCNx16       "hx" -#define SCNX16       "hX" -#define SCNoLEAST16  "ho" -#define SCNuLEAST16  "hu" -#define SCNxLEAST16  "hx" -#define SCNXLEAST16  "hX" -#define SCNoFAST16   "ho" -#define SCNuFAST16   "hu" -#define SCNxFAST16   "hx" -#define SCNXFAST16   "hX" - -#define SCNo32       "lo" -#define SCNu32       "lu" -#define SCNx32       "lx" -#define SCNX32       "lX" -#define SCNoLEAST32  "lo" -#define SCNuLEAST32  "lu" -#define SCNxLEAST32  "lx" -#define SCNXLEAST32  "lX" -#define SCNoFAST32   "lo" -#define SCNuFAST32   "lu" -#define SCNxFAST32   "lx" -#define SCNXFAST32   "lX" - -#define SCNo64       "I64o" -#define SCNu64       "I64u" -#define SCNx64       "I64x" -#define SCNX64       "I64X" -#define SCNoLEAST64  "I64o" -#define SCNuLEAST64  "I64u" -#define SCNxLEAST64  "I64x" -#define SCNXLEAST64  "I64X" -#define SCNoFAST64   "I64o" -#define SCNuFAST64   "I64u" -#define SCNxFAST64   "I64x" -#define SCNXFAST64   "I64X" - -#define SCNoMAX     "I64o" -#define SCNuMAX     "I64u" -#define SCNxMAX     "I64x" -#define SCNXMAX     "I64X" - -#ifdef _WIN64 // [ -#  define SCNoPTR     "I64o" -#  define SCNuPTR     "I64u" -#  define SCNxPTR     "I64x" -#  define SCNXPTR     "I64X" -#else  // _WIN64 ][ -#  define SCNoPTR     "lo" -#  define SCNuPTR     "lu" -#  define SCNxPTR     "lx" -#  define SCNXPTR     "lX" -#endif  // _WIN64 ] - -// 7.8.2 Functions for greatest-width integer types - -// 7.8.2.1 The imaxabs function -#define imaxabs _abs64 - -// 7.8.2.2 The imaxdiv function - -// This is modified version of div() function from Microsoft's div.c found -// in %MSVC.NET%\crt\src\div.c -#ifdef STATIC_IMAXDIV // [ -static -#else // STATIC_IMAXDIV ][ -_inline -#endif // STATIC_IMAXDIV ] -imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) -{ -   imaxdiv_t result; - -   result.quot = numer / denom; -   result.rem = numer % denom; - -   if (numer < 0 && result.rem > 0) { -      // did division wrong; must fix up -      ++result.quot; -      result.rem -= denom; -   } - -   return result; -} - -// 7.8.2.3 The strtoimax and strtoumax functions -#define strtoimax _strtoi64 -#define strtoumax _strtoui64 - -// 7.8.2.4 The wcstoimax and wcstoumax functions -#define wcstoimax _wcstoi64 -#define wcstoumax _wcstoui64 - - -#endif // _MSC_INTTYPES_H_ ] diff --git a/host/cmake/msvc/stdint.h b/host/cmake/msvc/stdint.h deleted file mode 100644 index 15333b467..000000000 --- a/host/cmake/msvc/stdint.h +++ /dev/null @@ -1,226 +0,0 @@ -// ISO C9x  compliant stdint.h for Microsoft Visual Studio -// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124  -//  -//  Copyright (c) 2006 Alexander Chemeris -//  -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -//  -//   1. Redistributions of source code must retain the above copyright notice, -//      this list of conditions and the following disclaimer. -//  -//   2. Redistributions in binary form must reproduce the above copyright -//      notice, this list of conditions and the following disclaimer in the -//      documentation and/or other materials provided with the distribution. -//  -//   3. The name of the author may be used to endorse or promote products -//      derived from this software without specific prior written permission. -//  -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED -// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  -// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -//  -/////////////////////////////////////////////////////////////////////////////// - -#ifndef _MSC_VER // [ -#error "Use this header only with Microsoft Visual C++ compilers!" -#endif // _MSC_VER ] - -#ifndef _MSC_STDINT_H_ // [ -#define _MSC_STDINT_H_ - -#if _MSC_VER > 1000 -#pragma once -#endif - -#include <limits.h> - -// For Visual Studio 6 in C++ mode wrap <wchar.h> include with 'extern "C++" {}' -// or compiler give many errors like this: -//   error C2733: second C linkage of overloaded function 'wmemchr' not allowed -#if (_MSC_VER < 1300) && defined(__cplusplus) -   extern "C++" { -#endif  -#     include <wchar.h> -#if (_MSC_VER < 1300) && defined(__cplusplus) -   } -#endif - -// 7.18.1 Integer types - -// 7.18.1.1 Exact-width integer types -typedef __int8            int8_t; -typedef __int16           int16_t; -typedef __int32           int32_t; -typedef __int64           int64_t; -typedef unsigned __int8   uint8_t; -typedef unsigned __int16  uint16_t; -typedef unsigned __int32  uint32_t; -typedef unsigned __int64  uint64_t; - -// 7.18.1.2 Minimum-width integer types -typedef int8_t    int_least8_t; -typedef int16_t   int_least16_t; -typedef int32_t   int_least32_t; -typedef int64_t   int_least64_t; -typedef uint8_t   uint_least8_t; -typedef uint16_t  uint_least16_t; -typedef uint32_t  uint_least32_t; -typedef uint64_t  uint_least64_t; - -// 7.18.1.3 Fastest minimum-width integer types -typedef int8_t    int_fast8_t; -typedef int16_t   int_fast16_t; -typedef int32_t   int_fast32_t; -typedef int64_t   int_fast64_t; -typedef uint8_t   uint_fast8_t; -typedef uint16_t  uint_fast16_t; -typedef uint32_t  uint_fast32_t; -typedef uint64_t  uint_fast64_t; - -// 7.18.1.4 Integer types capable of holding object pointers -#ifdef _WIN64 // [ -   typedef __int64           intptr_t; -   typedef unsigned __int64  uintptr_t; -#else // _WIN64 ][ -   typedef int               intptr_t; -   typedef unsigned int      uintptr_t; -#endif // _WIN64 ] - -// 7.18.1.5 Greatest-width integer types -typedef int64_t   intmax_t; -typedef uint64_t  uintmax_t; - - -// 7.18.2 Limits of specified-width integer types - -#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [   See footnote 220 at page 257 and footnote 221 at page 259 - -// 7.18.2.1 Limits of exact-width integer types -#define INT8_MIN     ((int8_t)_I8_MIN) -#define INT8_MAX     _I8_MAX -#define INT16_MIN    ((int16_t)_I16_MIN) -#define INT16_MAX    _I16_MAX -#define INT32_MIN    ((int32_t)_I32_MIN) -#define INT32_MAX    _I32_MAX -#define INT64_MIN    ((int64_t)_I64_MIN) -#define INT64_MAX    _I64_MAX -#define UINT8_MAX    _UI8_MAX -#define UINT16_MAX   _UI16_MAX -#define UINT32_MAX   _UI32_MAX -#define UINT64_MAX   _UI64_MAX - -// 7.18.2.2 Limits of minimum-width integer types -#define INT_LEAST8_MIN    INT8_MIN -#define INT_LEAST8_MAX    INT8_MAX -#define INT_LEAST16_MIN   INT16_MIN -#define INT_LEAST16_MAX   INT16_MAX -#define INT_LEAST32_MIN   INT32_MIN -#define INT_LEAST32_MAX   INT32_MAX -#define INT_LEAST64_MIN   INT64_MIN -#define INT_LEAST64_MAX   INT64_MAX -#define UINT_LEAST8_MAX   UINT8_MAX -#define UINT_LEAST16_MAX  UINT16_MAX -#define UINT_LEAST32_MAX  UINT32_MAX -#define UINT_LEAST64_MAX  UINT64_MAX - -// 7.18.2.3 Limits of fastest minimum-width integer types -#define INT_FAST8_MIN    INT8_MIN -#define INT_FAST8_MAX    INT8_MAX -#define INT_FAST16_MIN   INT16_MIN -#define INT_FAST16_MAX   INT16_MAX -#define INT_FAST32_MIN   INT32_MIN -#define INT_FAST32_MAX   INT32_MAX -#define INT_FAST64_MIN   INT64_MIN -#define INT_FAST64_MAX   INT64_MAX -#define UINT_FAST8_MAX   UINT8_MAX -#define UINT_FAST16_MAX  UINT16_MAX -#define UINT_FAST32_MAX  UINT32_MAX -#define UINT_FAST64_MAX  UINT64_MAX - -// 7.18.2.4 Limits of integer types capable of holding object pointers -#ifdef _WIN64 // [ -#  define INTPTR_MIN   INT64_MIN -#  define INTPTR_MAX   INT64_MAX -#  define UINTPTR_MAX  UINT64_MAX -#else // _WIN64 ][ -#  define INTPTR_MIN   INT32_MIN -#  define INTPTR_MAX   INT32_MAX -#  define UINTPTR_MAX  UINT32_MAX -#endif // _WIN64 ] - -// 7.18.2.5 Limits of greatest-width integer types -#define INTMAX_MIN   INT64_MIN -#define INTMAX_MAX   INT64_MAX -#define UINTMAX_MAX  UINT64_MAX - -// 7.18.3 Limits of other integer types - -#ifdef _WIN64 // [ -#  define PTRDIFF_MIN  _I64_MIN -#  define PTRDIFF_MAX  _I64_MAX -#else  // _WIN64 ][ -#  define PTRDIFF_MIN  _I32_MIN -#  define PTRDIFF_MAX  _I32_MAX -#endif  // _WIN64 ] - -#define SIG_ATOMIC_MIN  INT_MIN -#define SIG_ATOMIC_MAX  INT_MAX - -#ifndef SIZE_MAX // [ -#  ifdef _WIN64 // [ -#     define SIZE_MAX  _UI64_MAX -#  else // _WIN64 ][ -#     define SIZE_MAX  _UI32_MAX -#  endif // _WIN64 ] -#endif // SIZE_MAX ] - -// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h> -#ifndef WCHAR_MIN // [ -#  define WCHAR_MIN  0 -#endif  // WCHAR_MIN ] -#ifndef WCHAR_MAX // [ -#  define WCHAR_MAX  _UI16_MAX -#endif  // WCHAR_MAX ] - -#define WINT_MIN  0 -#define WINT_MAX  _UI16_MAX - -#endif // __STDC_LIMIT_MACROS ] - - -// 7.18.4 Limits of other integer types - -#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [   See footnote 224 at page 260 - -// 7.18.4.1 Macros for minimum-width integer constants - -#define INT8_C(val)  val##i8 -#define INT16_C(val) val##i16 -#define INT32_C(val) val##i32 -#define INT64_C(val) val##i64 - -#define UINT8_C(val)  val##ui8 -#define UINT16_C(val) val##ui16 -#define UINT32_C(val) val##ui32 -#define UINT64_C(val) val##ui64 - -// 7.18.4.2 Macros for greatest-width integer constants -#ifndef INTMAX_C -#define INTMAX_C   INT64_C -#endif -#ifndef UINTMAX_C -#define UINTMAX_C  UINT64_C -#endif - -#endif // __STDC_CONSTANT_MACROS ] - - -#endif // _MSC_STDINT_H_ ] diff --git a/host/docs/CMakeLists.txt b/host/docs/CMakeLists.txt index 3090d3f80..580295235 100644 --- a/host/docs/CMakeLists.txt +++ b/host/docs/CMakeLists.txt @@ -63,7 +63,6 @@ ENDIF(ENABLE_MANUAL)  ########################################################################  # Setup API documentation (using Doxygen)  ######################################################################## -MESSAGE(STATUS "")  LIBUHD_REGISTER_COMPONENT("API/Doxygen" ENABLE_DOXYGEN ON "DOXYGEN_FOUND" OFF OFF)  OPTION(ENABLE_DOXYGEN_FULL "Use Doxygen to document the entire source tree (not just API)" OFF) @@ -90,7 +89,6 @@ ENDIF(ENABLE_DOXYGEN)  ########################################################################  # Run Doxygen (on code and/or manual, depending on CMake flags)  ######################################################################## -MESSAGE(STATUS "")  IF(ENABLE_MANUAL_OR_DOXYGEN)      #generate the doxygen configuration file      SET(CMAKE_CURRENT_BINARY_DIR_DOXYGEN ${CMAKE_CURRENT_BINARY_DIR}/doxygen) @@ -133,7 +131,6 @@ SET(man_page_sources  ########################################################################  # Setup man pages  ######################################################################## -MESSAGE(STATUS "")  FIND_PACKAGE(GZip)  # No elegant way in CMake to reverse a boolean diff --git a/host/include/uhd/types/CMakeLists.txt b/host/include/uhd/types/CMakeLists.txt index 3f34782e2..3af395eeb 100644 --- a/host/include/uhd/types/CMakeLists.txt +++ b/host/include/uhd/types/CMakeLists.txt @@ -33,6 +33,7 @@ UHD_INSTALL(FILES      sensors.hpp      serial.hpp      sid.hpp +    stdint.hpp      stream_cmd.hpp      time_spec.hpp      tune_request.hpp diff --git a/host/include/uhd/types/stdint.hpp b/host/include/uhd/types/stdint.hpp new file mode 100644 index 000000000..cccb6b157 --- /dev/null +++ b/host/include/uhd/types/stdint.hpp @@ -0,0 +1,53 @@ +// +// 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_STDINT_HPP +#define INCLUDED_UHD_TYPES_STDINT_HPP + +#include <boost/cstdint.hpp> + +using boost::int8_t; +using boost::uint8_t; +using boost::int16_t; +using boost::uint16_t; +using boost::int32_t; +using boost::uint32_t; +using boost::int64_t; +using boost::uint64_t; + +using boost::int_least8_t; +using boost::uint_least8_t; +using boost::int_least16_t; +using boost::uint_least16_t; +using boost::int_least32_t; +using boost::uint_least32_t; +using boost::int_least64_t; +using boost::uint_least64_t; + +using boost::int_fast8_t; +using boost::uint_fast8_t; +using boost::int_fast16_t; +using boost::uint_fast16_t; +using boost::int_fast32_t; +using boost::uint_fast32_t; +using boost::int_fast64_t; +using boost::uint_fast64_t; + +using boost::intptr_t; +using boost::uintptr_t; + +#endif /* INCLUDED_UHD_TYPES_STDINT_HPP */ diff --git a/host/include/uhd/usrp/CMakeLists.txt b/host/include/uhd/usrp/CMakeLists.txt index e974f808d..2d3717357 100644 --- a/host/include/uhd/usrp/CMakeLists.txt +++ b/host/include/uhd/usrp/CMakeLists.txt @@ -26,6 +26,7 @@ UHD_INSTALL(FILES      ### utilities ###      gps_ctrl.hpp +    gpio_defs.hpp      mboard_eeprom.hpp      subdev_spec.hpp diff --git a/host/include/uhd/usrp/dboard_iface.hpp b/host/include/uhd/usrp/dboard_iface.hpp index f8f318a40..c3a3a4e00 100644 --- a/host/include/uhd/usrp/dboard_iface.hpp +++ b/host/include/uhd/usrp/dboard_iface.hpp @@ -22,6 +22,7 @@  #include <uhd/utils/pimpl.hpp>  #include <uhd/types/serial.hpp>  #include <uhd/types/time_spec.hpp> +#include <uhd/usrp/gpio_defs.hpp>  #include <boost/shared_ptr.hpp>  #include <boost/cstdint.hpp>  #include <string> @@ -67,14 +68,6 @@ public:          UNIT_TX = int('t')      }; -    //! possible atr registers -    enum atr_reg_t{ -        ATR_REG_IDLE        = int('i'), -        ATR_REG_TX_ONLY     = int('t'), -        ATR_REG_RX_ONLY     = int('r'), -        ATR_REG_FULL_DUPLEX = int('f') -    }; -      //! aux dac selection enums (per unit)      enum aux_dac_t{          AUX_DAC_A = int('a'), @@ -89,6 +82,8 @@ public:          AUX_ADC_B = int('b')      }; +    typedef uhd::usrp::gpio_atr::gpio_atr_reg_t atr_reg_t; +      /*!       * Get special properties information for this dboard slot.       * This call helps the dboard code to handle implementation diff --git a/host/include/uhd/usrp/gpio_defs.hpp b/host/include/uhd/usrp/gpio_defs.hpp new file mode 100644 index 000000000..c32f22f28 --- /dev/null +++ b/host/include/uhd/usrp/gpio_defs.hpp @@ -0,0 +1,70 @@ +// +// Copyright 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 +// 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_LIBUHD_USRP_GPIO_DEFS_HPP +#define INCLUDED_LIBUHD_USRP_GPIO_DEFS_HPP + +#include <uhd/config.hpp> +#include <boost/assign.hpp> +#include <boost/utility.hpp> +#include <map> + +namespace uhd { namespace usrp { namespace gpio_atr { + +enum gpio_atr_reg_t { +    ATR_REG_IDLE        = int('i'), +    ATR_REG_TX_ONLY     = int('t'), +    ATR_REG_RX_ONLY     = int('r'), +    ATR_REG_FULL_DUPLEX = int('f') +}; + +enum gpio_atr_mode_t { +    MODE_ATR  = 0,   //Output driven by the auto-transmit-receive engine +    MODE_GPIO = 1    //Output value is static +}; + +enum gpio_ddr_t { +    DDR_INPUT   = 0, +    DDR_OUTPUT  = 1 +}; + +enum gpio_attr_t { +    GPIO_CTRL, +    GPIO_DDR, +    GPIO_OUT, +    GPIO_ATR_0X, +    GPIO_ATR_RX, +    GPIO_ATR_TX, +    GPIO_ATR_XX +}; + +typedef std::map<gpio_attr_t, std::string> gpio_attr_map_t; + +static const gpio_attr_map_t gpio_attr_map = +    boost::assign::map_list_of +        (GPIO_CTRL,   "CTRL") +        (GPIO_DDR,    "DDR") +        (GPIO_OUT,    "OUT") +        (GPIO_ATR_0X, "ATR_0X") +        (GPIO_ATR_RX, "ATR_RX") +        (GPIO_ATR_TX, "ATR_TX") +        (GPIO_ATR_XX, "ATR_XX") +; + +}}} //namespaces + +#endif /* INCLUDED_LIBUHD_USRP_GPIO_DEFS_HPP */ diff --git a/host/include/uhd/utils/soft_register.hpp b/host/include/uhd/utils/soft_register.hpp index a2c34a4ec..665876e73 100644 --- a/host/include/uhd/utils/soft_register.hpp +++ b/host/include/uhd/utils/soft_register.hpp @@ -223,7 +223,7 @@ public:                  _soft_copy.mark_clean();              }          } else { -            throw uhd::not_implemented_error("soft_register is not writable."); +            throw uhd::not_implemented_error("soft_register is not writable or uninitialized.");          }      } @@ -244,7 +244,7 @@ public:              }              _soft_copy.mark_clean();          } else { -            throw uhd::not_implemented_error("soft_register is not readable."); +            throw uhd::not_implemented_error("soft_register is not readable or uninitialized.");          }      } diff --git a/host/include/uhd/version.hpp.in b/host/include/uhd/version.hpp.in index e2c64812d..bfa0b904a 100644 --- a/host/include/uhd/version.hpp.in +++ b/host/include/uhd/version.hpp.in @@ -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 @@ -27,7 +27,7 @@   * The format is oldest API compatible release - ABI compat number.   * The compatibility number allows pre-release ABI to be versioned.   */ -#define UHD_VERSION_ABI_STRING "3.9.0-0" +#define UHD_VERSION_ABI_STRING "3.10.0-0"  /*!   * A macro to check UHD version at compile-time. diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt index f74af1f29..07775895d 100644 --- a/host/lib/CMakeLists.txt +++ b/host/lib/CMakeLists.txt @@ -65,6 +65,25 @@ MACRO(INCLUDE_SUBDIRECTORY subdir)  ENDMACRO(INCLUDE_SUBDIRECTORY)  ######################################################################## +# Register lower level components +######################################################################## +MESSAGE(STATUS "") +# Dependencies +FIND_PACKAGE(USB1) +FIND_PACKAGE(GPSD) +LIBUHD_REGISTER_COMPONENT("USB" ENABLE_USB ON "ENABLE_LIBUHD;LIBUSB_FOUND" OFF OFF) +LIBUHD_REGISTER_COMPONENT("GPSD" ENABLE_GPSD OFF "ENABLE_LIBUHD;ENABLE_GPSD;LIBGPS_FOUND" OFF OFF) +# Devices +LIBUHD_REGISTER_COMPONENT("B100" ENABLE_B100 ON "ENABLE_LIBUHD;ENABLE_USB" OFF OFF) +LIBUHD_REGISTER_COMPONENT("B200" ENABLE_B200 ON "ENABLE_LIBUHD;ENABLE_USB" OFF OFF) +LIBUHD_REGISTER_COMPONENT("E100" ENABLE_E100 OFF "ENABLE_LIBUHD;LINUX" OFF OFF) +LIBUHD_REGISTER_COMPONENT("E300" ENABLE_E300 OFF "ENABLE_LIBUHD" OFF OFF) +LIBUHD_REGISTER_COMPONENT("USRP1" ENABLE_USRP1 ON "ENABLE_LIBUHD;ENABLE_USB" OFF OFF) +LIBUHD_REGISTER_COMPONENT("USRP2" ENABLE_USRP2 ON "ENABLE_LIBUHD" OFF OFF) +LIBUHD_REGISTER_COMPONENT("X300" ENABLE_X300 ON "ENABLE_LIBUHD" OFF OFF) +LIBUHD_REGISTER_COMPONENT("OctoClock" ENABLE_OCTOCLOCK ON "ENABLE_LIBUHD" OFF OFF) + +########################################################################  # Include subdirectories (different than add)  ########################################################################  INCLUDE_SUBDIRECTORY(ic_reg_maps) diff --git a/host/lib/convert/convert_item32.cpp b/host/lib/convert/convert_item32.cpp index 57bd64860..d52b47a1a 100644 --- a/host/lib/convert/convert_item32.cpp +++ b/host/lib/convert/convert_item32.cpp @@ -38,7 +38,10 @@      _DECLARE_ITEM32_CONVERTER(cpu_type, sc8) \      _DECLARE_ITEM32_CONVERTER(cpu_type, sc16) +/* Create sc16<->sc16,sc8(otw) */  DECLARE_ITEM32_CONVERTER(sc16) +/* Create fc32<->sc16,sc8(otw) */  DECLARE_ITEM32_CONVERTER(fc32) +/* Create fc64<->sc16,sc8(otw) */  DECLARE_ITEM32_CONVERTER(fc64)  _DECLARE_ITEM32_CONVERTER(sc8, sc8) diff --git a/host/lib/convert/gen_convert_general.py b/host/lib/convert/gen_convert_general.py index 4f9eeb747..5c62d51df 100644 --- a/host/lib/convert/gen_convert_general.py +++ b/host/lib/convert/gen_convert_general.py @@ -39,30 +39,37 @@ DECLARE_CONVERTER(item32, 1, item32, 1, PRIORITY_GENERAL) {  }  """ -TMPL_CONV_GEN2_ITEM32 = """ -DECLARE_CONVERTER(item32, 1, sc16_item32_{end}, 1, PRIORITY_GENERAL) {{ +# Some 32-bit types converters are also defined in convert_item32.cpp to +# take care of quirks such as I/Q ordering on the wire etc. +TMPL_CONV_ITEM32 = """ +DECLARE_CONVERTER({in_type}, 1, {out_type}, 1, PRIORITY_GENERAL) {{      const item32_t *input = reinterpret_cast<const item32_t *>(inputs[0]);      item32_t *output = reinterpret_cast<item32_t *>(outputs[0]);      for (size_t i = 0; i < nsamps; i++) {{ -        output[i] = {to_wire}(input[i]); +        output[i] = {to_wire_or_host}(input[i]);      }}  }} +""" -DECLARE_CONVERTER(sc16_item32_{end}, 1, item32, 1, PRIORITY_GENERAL) {{ +# 64-bit data types are two consecutive item32 items +TMPL_CONV_ITEM64 = """ +DECLARE_CONVERTER({in_type}, 1, {out_type}, 1, PRIORITY_GENERAL) {{      const item32_t *input = reinterpret_cast<const item32_t *>(inputs[0]);      item32_t *output = reinterpret_cast<item32_t *>(outputs[0]); -    for (size_t i = 0; i < nsamps; i++) {{ -        output[i] = {to_host}(input[i]); +    // An item64 is two item32_t's +    for (size_t i = 0; i < nsamps * 2; i++) {{ +        output[i] = {to_wire_or_host}(input[i]);      }}  }}  """ -TMPL_CONV_U8 = """ -DECLARE_CONVERTER(u8, 1, u8_item32_{end}, 1, PRIORITY_GENERAL) {{ -    const boost::uint32_t *input = reinterpret_cast<const boost::uint32_t *>(inputs[0]); -    boost::uint32_t *output = reinterpret_cast<boost::uint32_t *>(outputs[0]); + +TMPL_CONV_U8S8 = """ +DECLARE_CONVERTER({us8}, 1, {us8}_item32_{end}, 1, PRIORITY_GENERAL) {{ +    const item32_t *input = reinterpret_cast<const item32_t *>(inputs[0]); +    item32_t *output = reinterpret_cast<item32_t *>(outputs[0]);      // 1) Copy all the 4-byte tuples      size_t n_words = nsamps / 4; @@ -72,8 +79,8 @@ DECLARE_CONVERTER(u8, 1, u8_item32_{end}, 1, PRIORITY_GENERAL) {{      // 2) If nsamps was not a multiple of 4, copy the rest by hand      size_t bytes_left = nsamps % 4;      if (bytes_left) {{ -        const u8_t *last_input_word  = reinterpret_cast<const u8_t *>(&input[n_words]); -        u8_t *last_output_word = reinterpret_cast<u8_t *>(&output[n_words]); +        const {us8}_t *last_input_word  = reinterpret_cast<const {us8}_t *>(&input[n_words]); +        {us8}_t *last_output_word = reinterpret_cast<{us8}_t *>(&output[n_words]);          for (size_t k = 0; k < bytes_left; k++) {{              last_output_word[k] = last_input_word[k];          }} @@ -81,9 +88,9 @@ DECLARE_CONVERTER(u8, 1, u8_item32_{end}, 1, PRIORITY_GENERAL) {{      }}  }} -DECLARE_CONVERTER(u8_item32_{end}, 1, u8, 1, PRIORITY_GENERAL) {{ -    const boost::uint32_t *input = reinterpret_cast<const boost::uint32_t *>(inputs[0]); -    boost::uint32_t *output = reinterpret_cast<boost::uint32_t *>(outputs[0]); +DECLARE_CONVERTER({us8}_item32_{end}, 1, {us8}, 1, PRIORITY_GENERAL) {{ +    const item32_t *input = reinterpret_cast<const item32_t *>(inputs[0]); +    item32_t *output = reinterpret_cast<item32_t *>(outputs[0]);      // 1) Copy all the 4-byte tuples      size_t n_words = nsamps / 4; @@ -93,9 +100,9 @@ DECLARE_CONVERTER(u8_item32_{end}, 1, u8, 1, PRIORITY_GENERAL) {{      // 2) If nsamps was not a multiple of 4, copy the rest by hand      size_t bytes_left = nsamps % 4;      if (bytes_left) {{ -        boost::uint32_t last_input_word = {to_host}(input[n_words]); -        const u8_t *last_input_word_ptr = reinterpret_cast<const u8_t *>(&last_input_word); -        u8_t *last_output_word = reinterpret_cast<u8_t *>(&output[n_words]); +        item32_t last_input_word = {to_host}(input[n_words]); +        const {us8}_t *last_input_word_ptr = reinterpret_cast<const {us8}_t *>(&last_input_word); +        {us8}_t *last_output_word = reinterpret_cast<{us8}_t *>(&output[n_words]);          for (size_t k = 0; k < bytes_left; k++) {{              last_output_word[k] = last_input_word_ptr[k];          }} @@ -103,6 +110,40 @@ DECLARE_CONVERTER(u8_item32_{end}, 1, u8, 1, PRIORITY_GENERAL) {{  }}  """ +TMPL_CONV_S16 = """ +DECLARE_CONVERTER(s16, 1, s16_item32_{end}, 1, PRIORITY_GENERAL) {{ +    const item32_t *input = reinterpret_cast<const item32_t *>(inputs[0]); +    item32_t *output = reinterpret_cast<item32_t *>(outputs[0]); + +    // 1) Copy all the 4-byte tuples +    size_t n_words = nsamps / 2; +    for (size_t i = 0; i < n_words; i++) {{ +        output[i] = {to_wire}(input[i]); +    }} +    // 2) If nsamps was not a multiple of 2, copy the last one by hand +    if (nsamps % 2) {{ +        item32_t tmp = item32_t(*reinterpret_cast<const s16_t *>(&input[n_words])); +        output[n_words] = {to_wire}(tmp); +    }} +}} + +DECLARE_CONVERTER(s16_item32_{end}, 1, s16, 1, PRIORITY_GENERAL) {{ +    const item32_t *input = reinterpret_cast<const item32_t *>(inputs[0]); +    item32_t *output = reinterpret_cast<item32_t *>(outputs[0]); + +    // 1) Copy all the 4-byte tuples +    size_t n_words = nsamps / 2; +    for (size_t i = 0; i < n_words; i++) {{ +        output[i] = {to_host}(input[i]); +    }} +    // 2) If nsamps was not a multiple of 2, copy the last one by hand +    if (nsamps % 2) {{ +        item32_t tmp = {to_host}(input[n_words]); +        *reinterpret_cast<s16_t *>(&output[n_words]) = s16_t(tmp); +    }} +}} +""" +  TMPL_CONV_USRP1_COMPLEX = """  DECLARE_CONVERTER(${cpu_type}, ${width}, sc16_item16_usrp1, 1, PRIORITY_GENERAL){      % for w in range(width): @@ -164,23 +205,52 @@ if __name__ == '__main__':      file = os.path.basename(__file__)      output = parse_tmpl(TMPL_HEADER, file=file) -    #generate complex converters for all gen2 platforms -    for end, to_host, to_wire in ( -        ('be', 'uhd::ntohx', 'uhd::htonx'), -        ('le', 'uhd::wtohx', 'uhd::htowx'), -    ): -        output += TMPL_CONV_GEN2_ITEM32.format( -                end=end, to_host=to_host, to_wire=to_wire -        ) -    #generate raw (u8) converters: +    ## Generate all data types that are exactly +    ## item32 or multiples thereof: +    for end in ('be', 'le'): +        host_to_wire = {'be': 'uhd::htonx', 'le': 'uhd::htowx'}[end] +        wire_to_host = {'be': 'uhd::ntohx', 'le': 'uhd::wtohx'}[end] +        # item32 types (sc16->sc16 is a special case because it defaults +        # to Q/I order on the wire: +        for in_type, out_type, to_wire_or_host in ( +                ('item32', 'sc16_item32_{end}', host_to_wire), +                ('sc16_item32_{end}', 'item32', wire_to_host), +                ('f32', 'f32_item32_{end}', host_to_wire), +                ('f32_item32_{end}', 'f32', wire_to_host), +        ): +            output += TMPL_CONV_ITEM32.format( +                    end=end, to_wire_or_host=to_wire_or_host, +                    in_type=in_type.format(end=end), out_type=out_type.format(end=end) +            ) +        # 2xitem32 types: +        for in_type, out_type in ( +                ('fc32', 'fc32_item32_{end}'), +                ('fc32_item32_{end}', 'fc32'), +        ): +            output += TMPL_CONV_ITEM64.format( +                    end=end, to_wire_or_host=to_wire_or_host, +                    in_type=in_type.format(end=end), out_type=out_type.format(end=end) +            ) + +    ## Real 16-Bit:      for end, to_host, to_wire in (          ('be', 'uhd::ntohx', 'uhd::htonx'),          ('le', 'uhd::wtohx', 'uhd::htowx'),      ): -        output += TMPL_CONV_U8.format( -                end=end, to_host=to_host, to_wire=to_wire +        output += TMPL_CONV_S16.format( +            end=end, to_host=to_host, to_wire=to_wire          ) +    ## Real 8-Bit Types: +    for us8 in ('u8', 's8'): +        for end, to_host, to_wire in ( +            ('be', 'uhd::ntohx', 'uhd::htonx'), +            ('le', 'uhd::wtohx', 'uhd::htowx'), +        ): +            output += TMPL_CONV_U8S8.format( +                    us8=us8, end=end, to_host=to_host, to_wire=to_wire +            ) +      #generate complex converters for usrp1 format (requires Cheetah)      for width in 1, 2, 4:          for cpu_type, do_scale in ( diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt index 6abc399b4..79c8a90b7 100644 --- a/host/lib/transport/CMakeLists.txt +++ b/host/lib/transport/CMakeLists.txt @@ -22,17 +22,15 @@  ########################################################################  # Include subdirectories (different than add)  ######################################################################## -INCLUDE_SUBDIRECTORY(nirio) +IF(ENABLE_X300) +    INCLUDE_SUBDIRECTORY(nirio) +ENDIF(ENABLE_X300)  ########################################################################  # Setup libusb  ######################################################################## -MESSAGE(STATUS "") -FIND_PACKAGE(USB1) - -LIBUHD_REGISTER_COMPONENT("USB" ENABLE_USB ON "ENABLE_LIBUHD;LIBUSB_FOUND" OFF OFF) -  IF(ENABLE_USB) +    MESSAGE(STATUS "")      MESSAGE(STATUS "USB support enabled via libusb.")      INCLUDE_DIRECTORIES(${LIBUSB_INCLUDE_DIRS})      LIBUHD_APPEND_LIBS(${LIBUSB_LIBRARIES}) @@ -128,10 +126,15 @@ LIBUHD_APPEND_SOURCES(      ${CMAKE_CURRENT_SOURCE_DIR}/buffer_pool.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/if_addrs.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/udp_simple.cpp -    ${CMAKE_CURRENT_SOURCE_DIR}/nirio_zero_copy.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/chdr.cpp  ) +IF(ENABLE_X300) +    LIBUHD_APPEND_SOURCES( +        ${CMAKE_CURRENT_SOURCE_DIR}/nirio_zero_copy.cpp +    ) +ENDIF(ENABLE_X300) +  # Verbose Debug output for send/recv  SET( UHD_TXRX_DEBUG_PRINTS OFF CACHE BOOL "Use verbose debug output for send/recv" )  OPTION( UHD_TXRX_DEBUG_PRINTS "Use verbose debug output for send/recv" "" ) diff --git a/host/lib/transport/nirio/lvbitx/CMakeLists.txt b/host/lib/transport/nirio/lvbitx/CMakeLists.txt index b9a2a9f15..5741a12f8 100644 --- a/host/lib/transport/nirio/lvbitx/CMakeLists.txt +++ b/host/lib/transport/nirio/lvbitx/CMakeLists.txt @@ -1,5 +1,5 @@  # -# Copyright 2013 Ettus Research LLC +# Copyright 2013,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 @@ -30,8 +30,8 @@ MACRO(LIBUHD_LVBITX_GEN_SOURCE_AND_BITSTREAM lvbitx binfile)      SET(IMAGES_PATH_OPT --uhd-images-path=${UHD_IMAGES_DIR})      ADD_CUSTOM_COMMAND( -        OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${lvbitxprefix}_lvbitx.hpp           OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${lvbitxprefix}_lvbitx.cpp +        OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${lvbitxprefix}_lvbitx.hpp          DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/process-lvbitx.py          DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/template_lvbitx.hpp          DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/template_lvbitx.cpp @@ -41,6 +41,7 @@ MACRO(LIBUHD_LVBITX_GEN_SOURCE_AND_BITSTREAM lvbitx binfile)      )      #make libuhd depend on the output file +    LIBUHD_APPEND_SOURCES(${CMAKE_CURRENT_BINARY_DIR}/${lvbitxprefix}_lvbitx.hpp)      LIBUHD_APPEND_SOURCES(${CMAKE_CURRENT_BINARY_DIR}/${lvbitxprefix}_lvbitx.cpp)  ENDMACRO(LIBUHD_LVBITX_GEN_SOURCE_AND_BITSTREAM) diff --git a/host/lib/transport/super_recv_packet_handler.hpp b/host/lib/transport/super_recv_packet_handler.hpp index 0f1f7ff3a..3fcf9c1e6 100644 --- a/host/lib/transport/super_recv_packet_handler.hpp +++ b/host/lib/transport/super_recv_packet_handler.hpp @@ -203,6 +203,12 @@ public:      //! Overload call to issue stream commands      void issue_stream_cmd(const stream_cmd_t &stream_cmd)      { +        if (stream_cmd.stream_now +                and stream_cmd.stream_mode != stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS +                and _props.size() > 1) { +            throw uhd::runtime_error("Attempting to do multi-channel receive with stream_now == true will result in misaligned channels. Aborting."); +        } +          for (size_t i = 0; i < _props.size(); i++)          {              if (_props[i].issue_stream_cmd) _props[i].issue_stream_cmd(stream_cmd); diff --git a/host/lib/usrp/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt index 5c9592970..a2b94b01c 100644 --- a/host/lib/usrp/CMakeLists.txt +++ b/host/lib/usrp/CMakeLists.txt @@ -18,8 +18,6 @@  ########################################################################  # This file included, use CMake directory variables  ######################################################################## -find_package(GPSD) -  INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})  LIBUHD_APPEND_SOURCES( @@ -43,8 +41,6 @@ IF(ENABLE_C_API)      )  ENDIF(ENABLE_C_API) -LIBUHD_REGISTER_COMPONENT("GPSD" ENABLE_GPSD OFF "ENABLE_LIBUHD;ENABLE_GPSD;LIBGPS_FOUND" OFF OFF) -  IF(ENABLE_GPSD)      LIBUHD_APPEND_SOURCES(          ${CMAKE_CURRENT_SOURCE_DIR}/gpsd_iface.cpp diff --git a/host/lib/usrp/b100/CMakeLists.txt b/host/lib/usrp/b100/CMakeLists.txt index 1558cd974..66129458c 100644 --- a/host/lib/usrp/b100/CMakeLists.txt +++ b/host/lib/usrp/b100/CMakeLists.txt @@ -22,8 +22,6 @@  ########################################################################  # Conditionally configure the B100 support  ######################################################################## -LIBUHD_REGISTER_COMPONENT("B100" ENABLE_B100 ON "ENABLE_LIBUHD;ENABLE_USB" OFF OFF) -  IF(ENABLE_B100)      LIBUHD_APPEND_SOURCES(          ${CMAKE_CURRENT_SOURCE_DIR}/b100_impl.cpp diff --git a/host/lib/usrp/b200/CMakeLists.txt b/host/lib/usrp/b200/CMakeLists.txt index 76710dc65..4b9e2de55 100644 --- a/host/lib/usrp/b200/CMakeLists.txt +++ b/host/lib/usrp/b200/CMakeLists.txt @@ -22,8 +22,6 @@  ########################################################################  # Conditionally configure the B200 support  ######################################################################## -LIBUHD_REGISTER_COMPONENT("B200" ENABLE_B200 ON "ENABLE_LIBUHD;ENABLE_USB" OFF OFF) -  IF(ENABLE_B200)      LIBUHD_APPEND_SOURCES(          ${CMAKE_CURRENT_SOURCE_DIR}/b200_image_loader.cpp diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp index ffce08567..3aaf28ab3 100644 --- a/host/lib/usrp/b200/b200_impl.cpp +++ b/host/lib/usrp/b200/b200_impl.cpp @@ -41,6 +41,7 @@  using namespace uhd;  using namespace uhd::usrp; +using namespace uhd::usrp::gpio_atr;  using namespace uhd::transport;  static const boost::posix_time::milliseconds REENUMERATION_TIMEOUT_MS(3000); @@ -656,15 +657,15 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s      ////////////////////////////////////////////////////////////////////      // front panel gpio      //////////////////////////////////////////////////////////////////// -    _radio_perifs[0].fp_gpio = gpio_core_200::make(_radio_perifs[0].ctrl, TOREG(SR_FP_GPIO), RB32_FP_GPIO); +    _radio_perifs[0].fp_gpio = gpio_atr_3000::make(_radio_perifs[0].ctrl, TOREG(SR_FP_GPIO), RB32_FP_GPIO);      BOOST_FOREACH(const gpio_attr_map_t::value_type attr, gpio_attr_map)      {              _tree->create<boost::uint32_t>(mb_path / "gpio" / "FP0" / attr.second)              .set(0) -            .subscribe(boost::bind(&b200_impl::set_fp_gpio, this, _radio_perifs[0].fp_gpio, attr.first, _1)); +            .subscribe(boost::bind(&gpio_atr_3000::set_gpio_attr, _radio_perifs[0].fp_gpio, attr.first, _1));      }      _tree->create<boost::uint32_t>(mb_path / "gpio" / "FP0" / "READBACK") -        .publish(boost::bind(&b200_impl::get_fp_gpio, this, _radio_perifs[0].fp_gpio)); +        .publish(boost::bind(&gpio_atr_3000::read_gpio, _radio_perifs[0].fp_gpio));      ////////////////////////////////////////////////////////////////////      // dboard eeproms but not really @@ -677,10 +678,14 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s      ////////////////////////////////////////////////////////////////////      // do some post-init tasks      //////////////////////////////////////////////////////////////////// - -    //init the clock rate to something reasonable -    double default_tick_rate = device_addr.cast<double>("master_clock_rate", ad936x_manager::DEFAULT_TICK_RATE); +    // Init the clock rate and the auto mcr appropriately +    if (not device_addr.has_key("master_clock_rate")) { +        UHD_MSG(status) << "Setting master clock rate selection to 'automatic'." << std::endl; +    } +    // We can automatically choose a master clock rate, but not if the user specifies one +    const double default_tick_rate = device_addr.cast<double>("master_clock_rate", ad936x_manager::DEFAULT_TICK_RATE);      _tree->access<double>(mb_path / "tick_rate").set(default_tick_rate); +    _tree->access<bool>(mb_path / "auto_tick_rate").set(not device_addr.has_key("master_clock_rate"));      //subdev spec contains full width of selections      subdev_spec_t rx_spec, tx_spec; @@ -704,12 +709,6 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s          _radio_perifs[i].ddc->set_host_rate(default_tick_rate / ad936x_manager::DEFAULT_DECIM);          _radio_perifs[i].duc->set_host_rate(default_tick_rate / ad936x_manager::DEFAULT_INTERP);      } -    // We can automatically choose a master clock rate, but not if the user specifies one -    _tree->access<bool>(mb_path / "auto_tick_rate").set(not device_addr.has_key("master_clock_rate")); -    if (not device_addr.has_key("master_clock_rate")) { -        UHD_MSG(status) << "Setting master clock rate selection to 'automatic'." << std::endl; -    } -  }  b200_impl::~b200_impl(void) @@ -753,14 +752,15 @@ void b200_impl::setup_radio(const size_t dspno)      ////////////////////////////////////////////////////////////////////      // Set up peripherals      //////////////////////////////////////////////////////////////////// -    perif.atr = gpio_core_200_32wo::make(perif.ctrl, TOREG(SR_ATR)); +    perif.atr = gpio_atr_3000::make_write_only(perif.ctrl, TOREG(SR_ATR)); +    perif.atr->set_atr_mode(MODE_ATR, 0xFFFFFFFF);      // create rx dsp control objects      perif.framer = rx_vita_core_3000::make(perif.ctrl, TOREG(SR_RX_CTRL));      perif.ddc = rx_dsp_core_3000::make(perif.ctrl, TOREG(SR_RX_DSP), true /*is_b200?*/);      perif.ddc->set_link_rate(10e9/8); //whatever      perif.ddc->set_mux("IQ", false, dspno == 1 ? true : false, dspno == 1 ? true : false);      perif.ddc->set_freq(rx_dsp_core_3000::DEFAULT_CORDIC_FREQ); -    perif.deframer = tx_vita_core_3000::make(perif.ctrl, TOREG(SR_TX_CTRL)); +    perif.deframer = tx_vita_core_3000::make_no_radio_buff(perif.ctrl, TOREG(SR_TX_CTRL));      perif.duc = tx_dsp_core_3000::make(perif.ctrl, TOREG(SR_TX_DSP));      perif.duc->set_link_rate(10e9/8); //whatever      perif.duc->set_freq(tx_dsp_core_3000::DEFAULT_CORDIC_FREQ); @@ -792,7 +792,6 @@ void b200_impl::setup_radio(const size_t dspno)      // create tx dsp control objects      ////////////////////////////////////////////////////////////////////      _tree->access<double>(mb_path / "tick_rate") -        .subscribe(boost::bind(&tx_vita_core_3000::set_tick_rate, perif.deframer, _1))          .subscribe(boost::bind(&tx_dsp_core_3000::set_tick_rate, perif.duc, _1));      const fs_path tx_dsp_path = mb_path / "tx_dsps" / dspno;      perif.duc->populate_subtree(_tree->subtree(tx_dsp_path)); @@ -964,27 +963,6 @@ void b200_impl::set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &mb_eeprom)      mb_eeprom.commit(*_iface, "B200");  } - -boost::uint32_t b200_impl::get_fp_gpio(gpio_core_200::sptr gpio) -{ -    return boost::uint32_t(gpio->read_gpio(dboard_iface::UNIT_RX)); -} - -void b200_impl::set_fp_gpio(gpio_core_200::sptr gpio, const gpio_attr_t attr, const boost::uint32_t value) -{ -    switch (attr) -    { -    case GPIO_CTRL:   return gpio->set_pin_ctrl(dboard_iface::UNIT_RX, value); -    case GPIO_DDR:    return gpio->set_gpio_ddr(dboard_iface::UNIT_RX, value); -    case GPIO_OUT:    return gpio->set_gpio_out(dboard_iface::UNIT_RX, value); -    case GPIO_ATR_0X: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, value); -    case GPIO_ATR_RX: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY, value); -    case GPIO_ATR_TX: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY, value); -    case GPIO_ATR_XX: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, value); -    default:        UHD_THROW_INVALID_CODE_PATH(); -    } -} -  /***********************************************************************   * Reference time and clock   **********************************************************************/ @@ -1154,11 +1132,11 @@ void b200_impl::update_atrs(void)          if (enb_rx and enb_tx) fd = STATE_FDX1_TXRX;          if (enb_rx and not enb_tx) fd = rxonly;          if (not enb_rx and enb_tx) fd = txonly; -        gpio_core_200_32wo::sptr atr = perif.atr; -        atr->set_atr_reg(dboard_iface::ATR_REG_IDLE, STATE_OFF); -        atr->set_atr_reg(dboard_iface::ATR_REG_RX_ONLY, rxonly); -        atr->set_atr_reg(dboard_iface::ATR_REG_TX_ONLY, txonly); -        atr->set_atr_reg(dboard_iface::ATR_REG_FULL_DUPLEX, fd); +        gpio_atr_3000::sptr atr = perif.atr; +        atr->set_atr_reg(ATR_REG_IDLE, STATE_OFF); +        atr->set_atr_reg(ATR_REG_RX_ONLY, rxonly); +        atr->set_atr_reg(ATR_REG_TX_ONLY, txonly); +        atr->set_atr_reg(ATR_REG_FULL_DUPLEX, fd);      }      if (_radio_perifs.size() > _fe2 and _radio_perifs[_fe2].atr)      { @@ -1172,11 +1150,11 @@ void b200_impl::update_atrs(void)          if (enb_rx and enb_tx) fd = STATE_FDX2_TXRX;          if (enb_rx and not enb_tx) fd = rxonly;          if (not enb_rx and enb_tx) fd = txonly; -        gpio_core_200_32wo::sptr atr = perif.atr; -        atr->set_atr_reg(dboard_iface::ATR_REG_IDLE, STATE_OFF); -        atr->set_atr_reg(dboard_iface::ATR_REG_RX_ONLY, rxonly); -        atr->set_atr_reg(dboard_iface::ATR_REG_TX_ONLY, txonly); -        atr->set_atr_reg(dboard_iface::ATR_REG_FULL_DUPLEX, fd); +        gpio_atr_3000::sptr atr = perif.atr; +        atr->set_atr_reg(ATR_REG_IDLE, STATE_OFF); +        atr->set_atr_reg(ATR_REG_RX_ONLY, rxonly); +        atr->set_atr_reg(ATR_REG_TX_ONLY, txonly); +        atr->set_atr_reg(ATR_REG_FULL_DUPLEX, fd);      }  } diff --git a/host/lib/usrp/b200/b200_impl.hpp b/host/lib/usrp/b200/b200_impl.hpp index 25fef7d4b..b406572fb 100644 --- a/host/lib/usrp/b200/b200_impl.hpp +++ b/host/lib/usrp/b200/b200_impl.hpp @@ -27,7 +27,7 @@  #include "rx_vita_core_3000.hpp"  #include "tx_vita_core_3000.hpp"  #include "time_core_3000.hpp" -#include "gpio_core_200.hpp" +#include "gpio_atr_3000.hpp"  #include "radio_ctrl_core_3000.hpp"  #include "rx_dsp_core_3000.hpp"  #include "tx_dsp_core_3000.hpp" @@ -49,8 +49,8 @@  #include "recv_packet_demuxer_3000.hpp"  static const boost::uint8_t  B200_FW_COMPAT_NUM_MAJOR = 8;  static const boost::uint8_t  B200_FW_COMPAT_NUM_MINOR = 0; -static const boost::uint16_t B200_FPGA_COMPAT_NUM = 11; -static const boost::uint16_t B205_FPGA_COMPAT_NUM = 2; +static const boost::uint16_t B200_FPGA_COMPAT_NUM = 12; +static const boost::uint16_t B205_FPGA_COMPAT_NUM = 3;  static const double          B200_BUS_CLOCK_RATE = 100e6;  static const boost::uint32_t B200_GPSDO_ST_NONE = 0x83;  static const size_t B200_MAX_RATE_USB2              =  53248000; // bytes/s @@ -177,8 +177,8 @@ private:      struct radio_perifs_t      {          radio_ctrl_core_3000::sptr ctrl; -        gpio_core_200_32wo::sptr atr; -        gpio_core_200::sptr fp_gpio; +        uhd::usrp::gpio_atr::gpio_atr_3000::sptr atr; +        uhd::usrp::gpio_atr::gpio_atr_3000::sptr fp_gpio;          time_core_3000::sptr time64;          rx_vita_core_3000::sptr framer;          rx_dsp_core_3000::sptr ddc; @@ -226,9 +226,6 @@ private:      void update_enables(void);      void update_atrs(void); -    boost::uint32_t get_fp_gpio(gpio_core_200::sptr); -    void set_fp_gpio(gpio_core_200::sptr, const gpio_attr_t, const boost::uint32_t); -      double _tick_rate;      double get_tick_rate(void){return _tick_rate;}      double set_tick_rate(const double rate); diff --git a/host/lib/usrp/b200/b200_io_impl.cpp b/host/lib/usrp/b200/b200_io_impl.cpp index 7fcd04823..41b4b8a74 100644 --- a/host/lib/usrp/b200/b200_io_impl.cpp +++ b/host/lib/usrp/b200/b200_io_impl.cpp @@ -159,7 +159,6 @@ void b200_impl::update_tick_rate(const double new_tick_rate)          boost::shared_ptr<sph::send_packet_streamer> my_streamer =              boost::dynamic_pointer_cast<sph::send_packet_streamer>(perif.tx_streamer.lock());          if (my_streamer) my_streamer->set_tick_rate(new_tick_rate); -        perif.deframer->set_tick_rate(new_tick_rate);      }  } diff --git a/host/lib/usrp/common/ad9361_ctrl.hpp b/host/lib/usrp/common/ad9361_ctrl.hpp index 5c438ee9c..8cd75d539 100644 --- a/host/lib/usrp/common/ad9361_ctrl.hpp +++ b/host/lib/usrp/common/ad9361_ctrl.hpp @@ -89,8 +89,10 @@ public:      //! get the clock rate range for the frontend      static uhd::meta_range_t get_clock_rate_range(void)      { -        //return uhd::meta_range_t(220e3, 61.44e6); -        return uhd::meta_range_t(5e6, ad9361_device_t::AD9361_MAX_CLOCK_RATE); //5 MHz DCM low end +        return uhd::meta_range_t( +                ad9361_device_t::AD9361_MIN_CLOCK_RATE, +                ad9361_device_t::AD9361_MAX_CLOCK_RATE +        );      }      //! set the filter bandwidth for the frontend's analog low pass diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp b/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp index 0a8a61575..bb25379c0 100644 --- a/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp +++ b/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp @@ -91,6 +91,7 @@ int get_num_taps(int max_num_taps) {  }  const double ad9361_device_t::AD9361_MAX_GAIN        = 89.75; +const double ad9361_device_t::AD9361_MIN_CLOCK_RATE  = 220e3;  const double ad9361_device_t::AD9361_MAX_CLOCK_RATE  = 61.44e6;  const double ad9361_device_t::AD9361_CAL_VALID_WINDOW = 100e6;  // Max bandwdith is due to filter rolloff in analog filter stage @@ -770,7 +771,7 @@ void ad9361_device_t::_calibrate_rf_dc_offset()      size_t count = 0;      _io_iface->poke8(0x016, 0x02);      while (_io_iface->peek8(0x016) & 0x02) { -        if (count > 100) { +        if (count > 200) {              throw uhd::runtime_error("[ad9361_device_t] RF DC Offset Calibration Failure");              break;          } @@ -821,7 +822,7 @@ void ad9361_device_t::_calibrate_rx_quadrature()      size_t count = 0;      _io_iface->poke8(0x016, 0x20);      while (_io_iface->peek8(0x016) & 0x20) { -        if (count > 100) { +        if (count > 1000) {              throw uhd::runtime_error("[ad9361_device_t] Rx Quadrature Calibration Failure");              break;          } diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_device.h b/host/lib/usrp/common/ad9361_driver/ad9361_device.h index 66bc2e8b9..73b1d9a35 100644 --- a/host/lib/usrp/common/ad9361_driver/ad9361_device.h +++ b/host/lib/usrp/common/ad9361_driver/ad9361_device.h @@ -157,6 +157,7 @@ public:      //Constants      static const double AD9361_MAX_GAIN;      static const double AD9361_MAX_CLOCK_RATE; +    static const double AD9361_MIN_CLOCK_RATE;      static const double AD9361_CAL_VALID_WINDOW;      static const double AD9361_RECOMMENDED_MAX_BANDWIDTH;      static const double DEFAULT_RX_FREQ; diff --git a/host/lib/usrp/cores/CMakeLists.txt b/host/lib/usrp/cores/CMakeLists.txt index f28ae040f..7a0f6cc93 100644 --- a/host/lib/usrp/cores/CMakeLists.txt +++ b/host/lib/usrp/cores/CMakeLists.txt @@ -40,4 +40,6 @@ LIBUHD_APPEND_SOURCES(      ${CMAKE_CURRENT_SOURCE_DIR}/rx_dsp_core_3000.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/tx_dsp_core_3000.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/radio_ctrl_core_3000.cpp +    ${CMAKE_CURRENT_SOURCE_DIR}/gpio_atr_3000.cpp +    ${CMAKE_CURRENT_SOURCE_DIR}/dma_fifo_core_3000.cpp  ) diff --git a/host/lib/usrp/cores/dma_fifo_core_3000.cpp b/host/lib/usrp/cores/dma_fifo_core_3000.cpp new file mode 100644 index 000000000..1a9d5dd5c --- /dev/null +++ b/host/lib/usrp/cores/dma_fifo_core_3000.cpp @@ -0,0 +1,397 @@ +// +// 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/>. +// + +#include "dma_fifo_core_3000.hpp" +#include <uhd/exception.hpp> +#include <boost/thread/thread.hpp> //sleep +#include <uhd/utils/soft_register.hpp> +#include <uhd/utils/msg.hpp> + +using namespace uhd; + +#define SR_DRAM_BIST_BASE 16 + +dma_fifo_core_3000::~dma_fifo_core_3000(void) { +    /* NOP */ +} + +class dma_fifo_core_3000_impl : public dma_fifo_core_3000 +{ +protected: +    class rb_addr_reg_t : public soft_reg32_wo_t { +    public: +        UHD_DEFINE_SOFT_REG_FIELD(ADDR, /*width*/ 3, /*shift*/ 0);  //[2:0] + +        static const boost::uint32_t RB_FIFO_STATUS     = 0; +        static const boost::uint32_t RB_BIST_STATUS     = 1; +        static const boost::uint32_t RB_BIST_XFER_CNT   = 2; +        static const boost::uint32_t RB_BIST_CYC_CNT    = 3; + +        rb_addr_reg_t(boost::uint32_t base): +            soft_reg32_wo_t(base + 0) +        { +            //Initial values +            set(ADDR, RB_FIFO_STATUS); +        } +    }; + +    class fifo_ctrl_reg_t : public soft_reg32_wo_t { +    public: +        UHD_DEFINE_SOFT_REG_FIELD(CLEAR_FIFO,           /*width*/  1, /*shift*/  0);  //[0] +        UHD_DEFINE_SOFT_REG_FIELD(RD_SUPPRESS_EN,       /*width*/  1, /*shift*/  1);  //[1] +        UHD_DEFINE_SOFT_REG_FIELD(BURST_TIMEOUT,        /*width*/ 12, /*shift*/  4);  //[15:4] +        UHD_DEFINE_SOFT_REG_FIELD(RD_SUPPRESS_THRESH,   /*width*/ 16, /*shift*/ 16);  //[31:16] + +        fifo_ctrl_reg_t(boost::uint32_t base): +            soft_reg32_wo_t(base + 4) +        { +            //Initial values +            set(CLEAR_FIFO, 1); +            set(RD_SUPPRESS_EN, 0); +            set(BURST_TIMEOUT, 256); +            set(RD_SUPPRESS_THRESH, 0); +        } +    }; + +    class base_addr_reg_t : public soft_reg32_wo_t { +    public: +        UHD_DEFINE_SOFT_REG_FIELD(BASE_ADDR, /*width*/ 30, /*shift*/ 0);  //[29:0] + +        base_addr_reg_t(boost::uint32_t base): +            soft_reg32_wo_t(base + 8) +        { +            //Initial values +            set(BASE_ADDR, 0x00000000); +        } +    }; + +    class addr_mask_reg_t : public soft_reg32_wo_t { +    public: +        UHD_DEFINE_SOFT_REG_FIELD(ADDR_MASK, /*width*/ 30, /*shift*/ 0);  //[29:0] + +        addr_mask_reg_t(boost::uint32_t base): +            soft_reg32_wo_t(base + 12) +        { +            //Initial values +            set(ADDR_MASK, 0xFF000000); +        } +    }; + +    class bist_ctrl_reg_t : public soft_reg32_wo_t { +    public: +        UHD_DEFINE_SOFT_REG_FIELD(GO,               /*width*/ 1, /*shift*/ 0);  //[0] +        UHD_DEFINE_SOFT_REG_FIELD(CONTINUOUS_MODE,  /*width*/ 1, /*shift*/ 1);  //[1] +        UHD_DEFINE_SOFT_REG_FIELD(TEST_PATT,        /*width*/ 2, /*shift*/ 4);  //[5:4] + +        static const boost::uint32_t TEST_PATT_ZERO_ONE     = 0; +        static const boost::uint32_t TEST_PATT_CHECKERBOARD = 1; +        static const boost::uint32_t TEST_PATT_COUNT        = 2; +        static const boost::uint32_t TEST_PATT_COUNT_INV    = 3; + +        bist_ctrl_reg_t(boost::uint32_t base): +            soft_reg32_wo_t(base + 16) +        { +            //Initial values +            set(GO, 0); +            set(CONTINUOUS_MODE, 0); +            set(TEST_PATT, TEST_PATT_ZERO_ONE); +        } +    }; + +    class bist_cfg_reg_t : public soft_reg32_wo_t { +    public: +        UHD_DEFINE_SOFT_REG_FIELD(MAX_PKTS,         /*width*/ 18, /*shift*/ 0);  //[17:0] +        UHD_DEFINE_SOFT_REG_FIELD(MAX_PKT_SIZE,     /*width*/ 13, /*shift*/ 18); //[30:18] +        UHD_DEFINE_SOFT_REG_FIELD(PKT_SIZE_RAMP,    /*width*/ 1,  /*shift*/ 31); //[31] + +        bist_cfg_reg_t(boost::uint32_t base): +            soft_reg32_wo_t(base + 20) +        { +            //Initial values +            set(MAX_PKTS, 0); +            set(MAX_PKT_SIZE, 0); +            set(PKT_SIZE_RAMP, 0); +        } +    }; + +    class bist_delay_reg_t : public soft_reg32_wo_t { +    public: +        UHD_DEFINE_SOFT_REG_FIELD(TX_PKT_DELAY,     /*width*/ 16, /*shift*/ 0);  //[15:0] +        UHD_DEFINE_SOFT_REG_FIELD(RX_SAMP_DELAY,    /*width*/  8, /*shift*/ 16); //[23:16] + +        bist_delay_reg_t(boost::uint32_t base): +            soft_reg32_wo_t(base + 24) +        { +            //Initial values +            set(TX_PKT_DELAY, 0); +            set(RX_SAMP_DELAY, 0); +        } +    }; + +    class bist_sid_reg_t : public soft_reg32_wo_t { +    public: +        UHD_DEFINE_SOFT_REG_FIELD(SID,     /*width*/ 32, /*shift*/ 0);  //[31:0] + +        bist_sid_reg_t(boost::uint32_t base): +            soft_reg32_wo_t(base + 28) +        { +            //Initial values +            set(SID, 0); +        } +    }; + +public: +    class fifo_readback { +    public: +        fifo_readback(wb_iface::sptr iface,  const size_t base, const size_t rb_addr) : +            _iface(iface), _addr_reg(base), _rb_addr(rb_addr) +        { +            _addr_reg.initialize(*iface, true); +        } + +        bool is_fifo_instantiated() { +            boost::lock_guard<boost::mutex> lock(_mutex); +            _addr_reg.write(rb_addr_reg_t::ADDR, rb_addr_reg_t::RB_FIFO_STATUS); +            return _iface->peek32(_rb_addr) & 0x80000000; +        } + +        boost::uint32_t get_occupied_cnt() { +            boost::lock_guard<boost::mutex> lock(_mutex); +            _addr_reg.write(rb_addr_reg_t::ADDR, rb_addr_reg_t::RB_FIFO_STATUS); +            return _iface->peek32(_rb_addr) & 0x7FFFFFF; +        } + +        boost::uint32_t is_fifo_busy() { +            boost::lock_guard<boost::mutex> lock(_mutex); +            _addr_reg.write(rb_addr_reg_t::ADDR, rb_addr_reg_t::RB_FIFO_STATUS); +            return _iface->peek32(_rb_addr) & 0x40000000; +        } + +        struct bist_status_t { +            bool running; +            bool finished; +            boost::uint8_t error; +        }; + +        bist_status_t get_bist_status() { +            boost::lock_guard<boost::mutex> lock(_mutex); +            _addr_reg.write(rb_addr_reg_t::ADDR, rb_addr_reg_t::RB_BIST_STATUS); +            boost::uint32_t st32 = _iface->peek32(_rb_addr) & 0xF; +            bist_status_t status; +            status.running = st32 & 0x1; +            status.finished = st32 & 0x2; +            status.error = static_cast<boost::uint8_t>((st32>>2) & 0x3); +            return status; +        } + +        bool is_ext_bist_supported() { +            boost::lock_guard<boost::mutex> lock(_mutex); +            _addr_reg.write(rb_addr_reg_t::ADDR, rb_addr_reg_t::RB_BIST_STATUS); +            return _iface->peek32(_rb_addr) & 0x80000000; +        } + +        double get_xfer_ratio() { +            boost::lock_guard<boost::mutex> lock(_mutex); +            boost::uint32_t xfer_cnt = 0, cyc_cnt = 0; +            _addr_reg.write(rb_addr_reg_t::ADDR, rb_addr_reg_t::RB_BIST_XFER_CNT); +            xfer_cnt = _iface->peek32(_rb_addr); +            _addr_reg.write(rb_addr_reg_t::ADDR, rb_addr_reg_t::RB_BIST_CYC_CNT); +            cyc_cnt = _iface->peek32(_rb_addr); +            return (static_cast<double>(xfer_cnt)/cyc_cnt); +        } + +    private: +        wb_iface::sptr  _iface; +        rb_addr_reg_t   _addr_reg; +        const size_t    _rb_addr; +        boost::mutex    _mutex; +    }; + +public: +    dma_fifo_core_3000_impl(wb_iface::sptr iface, const size_t base, const size_t readback): +        _iface(iface), _base(base), _fifo_readback(iface, base, readback), +        _fifo_ctrl_reg(base), _base_addr_reg(base), _addr_mask_reg(base), +        _bist_ctrl_reg(base), _bist_cfg_reg(base), _bist_delay_reg(base), _bist_sid_reg(base) +    { +        _fifo_ctrl_reg.initialize(*iface, true); +        _base_addr_reg.initialize(*iface, true); +        _addr_mask_reg.initialize(*iface, true); +        _bist_ctrl_reg.initialize(*iface, true); +        _bist_cfg_reg.initialize(*iface, true); +        _has_ext_bist = _fifo_readback.is_ext_bist_supported(); +        if (_has_ext_bist) { +            _bist_delay_reg.initialize(*iface, true); +            _bist_sid_reg.initialize(*iface, true); +        } +        flush(); +    } + +    virtual void flush() { +        //Clear the FIFO and hold it in that state +        _fifo_ctrl_reg.write(fifo_ctrl_reg_t::CLEAR_FIFO, 1); +        //Re-arm the FIFO +        _wait_for_fifo_empty(); +        _fifo_ctrl_reg.write(fifo_ctrl_reg_t::CLEAR_FIFO, 0); +    } + +    virtual void resize(const boost::uint32_t base_addr, const boost::uint32_t size) { +        //Validate parameters +        if (size < 8192) throw uhd::runtime_error("DMA FIFO must be larger than 8KiB"); +        boost::uint32_t size_mask = size - 1; +        if (size & size_mask) throw uhd::runtime_error("DMA FIFO size must be a power of 2"); + +        //Clear the FIFO and hold it in that state +        _fifo_ctrl_reg.write(fifo_ctrl_reg_t::CLEAR_FIFO, 1); +        //Write base address and mask +        _base_addr_reg.write(base_addr_reg_t::BASE_ADDR, base_addr); +        _addr_mask_reg.write(addr_mask_reg_t::ADDR_MASK, ~size_mask); + +        //Re-arm the FIFO +        flush(); +    } + +    virtual boost::uint32_t get_bytes_occupied() { +        return _fifo_readback.get_occupied_cnt() * 8; +    } + +    virtual bool ext_bist_supported() { +        return _fifo_readback.is_ext_bist_supported(); +    } + +    virtual boost::uint8_t run_bist(bool finite = true, boost::uint32_t timeout_ms = 500) { +        return run_ext_bist(finite, 0, 0, 0, timeout_ms); +    } + +    virtual boost::uint8_t run_ext_bist( +        bool finite, +        boost::uint32_t rx_samp_delay, +        boost::uint32_t tx_pkt_delay, +        boost::uint32_t sid, +        boost::uint32_t timeout_ms = 500 +    ) { +        boost::lock_guard<boost::mutex> lock(_mutex); + +        _wait_for_bist_done(timeout_ms, true);          //Stop previous BIST and wait (if running) +        _bist_ctrl_reg.write(bist_ctrl_reg_t::GO, 0);   //Reset + +        _bist_cfg_reg.set(bist_cfg_reg_t::MAX_PKTS, (2^18)-1); +        _bist_cfg_reg.set(bist_cfg_reg_t::MAX_PKT_SIZE, 8000); +        _bist_cfg_reg.set(bist_cfg_reg_t::PKT_SIZE_RAMP, 0); +        _bist_cfg_reg.flush(); + +        if (_has_ext_bist) { +            _bist_delay_reg.set(bist_delay_reg_t::RX_SAMP_DELAY, rx_samp_delay); +            _bist_delay_reg.set(bist_delay_reg_t::TX_PKT_DELAY, tx_pkt_delay); +            _bist_delay_reg.flush(); + +            _bist_sid_reg.write(bist_sid_reg_t::SID, sid); +        } else { +            if (rx_samp_delay != 0 || tx_pkt_delay != 0 || sid != 0) { +                throw uhd::not_implemented_error( +                    "dma_fifo_core_3000: Runtime delay and SID support only available on FPGA images with extended BIST enabled"); +            } +        } + +        _bist_ctrl_reg.set(bist_ctrl_reg_t::TEST_PATT, bist_ctrl_reg_t::TEST_PATT_COUNT); +        _bist_ctrl_reg.set(bist_ctrl_reg_t::CONTINUOUS_MODE, finite ? 0 : 1); +        _bist_ctrl_reg.write(bist_ctrl_reg_t::GO, 1); + +        if (!finite) { +            boost::this_thread::sleep(boost::posix_time::milliseconds(timeout_ms)); +        } + +        _wait_for_bist_done(timeout_ms, !finite); +        if (!_fifo_readback.get_bist_status().finished) { +            throw uhd::runtime_error("dma_fifo_core_3000: DRAM BIST state machine is in a bad state."); +        } + +        return _fifo_readback.get_bist_status().error; +    } + +    virtual double get_bist_throughput(double fifo_clock_rate) { +        if (_has_ext_bist) { +            _wait_for_bist_done(1000); +            static const double BYTES_PER_CYC = 8; +            return _fifo_readback.get_xfer_ratio() * fifo_clock_rate * BYTES_PER_CYC; +        } else { +            throw uhd::not_implemented_error( +                "dma_fifo_core_3000: Throughput counter only available on FPGA images with extended BIST enabled"); +        } +    } + +private: +    void _wait_for_fifo_empty() +    { +        boost::posix_time::ptime start_time = boost::posix_time::microsec_clock::local_time(); +        boost::posix_time::time_duration elapsed; + +        while (_fifo_readback.is_fifo_busy()) { +            boost::this_thread::sleep(boost::posix_time::microsec(1000)); +            elapsed = boost::posix_time::microsec_clock::local_time() - start_time; +            if (elapsed.total_milliseconds() > 100) break; +        } +    } + +    void _wait_for_bist_done(boost::uint32_t timeout_ms, bool force_stop = false) +    { +        boost::posix_time::ptime start_time = boost::posix_time::microsec_clock::local_time(); +        boost::posix_time::time_duration elapsed; + +        while (_fifo_readback.get_bist_status().running) { +            if (force_stop) { +                _bist_ctrl_reg.write(bist_ctrl_reg_t::GO, 0); +                force_stop = false; +            } +            boost::this_thread::sleep(boost::posix_time::microsec(1000)); +            elapsed = boost::posix_time::microsec_clock::local_time() - start_time; +            if (elapsed.total_milliseconds() > timeout_ms) break; +        } +    } + +private: +    wb_iface::sptr  _iface; +    const size_t    _base; +    boost::mutex    _mutex; +    bool            _has_ext_bist; + +    fifo_readback       _fifo_readback; +    fifo_ctrl_reg_t     _fifo_ctrl_reg; +    base_addr_reg_t     _base_addr_reg; +    addr_mask_reg_t     _addr_mask_reg; +    bist_ctrl_reg_t     _bist_ctrl_reg; +    bist_cfg_reg_t      _bist_cfg_reg; +    bist_delay_reg_t    _bist_delay_reg; +    bist_sid_reg_t      _bist_sid_reg; +}; + +// +// Static make function +// +dma_fifo_core_3000::sptr dma_fifo_core_3000::make(wb_iface::sptr iface, const size_t set_base, const size_t rb_addr) +{ +    if (check(iface, set_base, rb_addr)) { +        return sptr(new dma_fifo_core_3000_impl(iface, set_base, rb_addr)); +    } else { +        throw uhd::runtime_error(""); +    } +} + +bool dma_fifo_core_3000::check(wb_iface::sptr iface, const size_t set_base, const size_t rb_addr) +{ +    dma_fifo_core_3000_impl::fifo_readback fifo_rb(iface, set_base, rb_addr); +    return fifo_rb.is_fifo_instantiated(); +} diff --git a/host/lib/usrp/cores/dma_fifo_core_3000.hpp b/host/lib/usrp/cores/dma_fifo_core_3000.hpp new file mode 100644 index 000000000..41430e5c3 --- /dev/null +++ b/host/lib/usrp/cores/dma_fifo_core_3000.hpp @@ -0,0 +1,86 @@ +// +// 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_LIBUHD_USRP_DMA_FIFO_CORE_3000_HPP +#define INCLUDED_LIBUHD_USRP_DMA_FIFO_CORE_3000_HPP + +#include <uhd/config.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/noncopyable.hpp> +#include <uhd/types/wb_iface.hpp> + + +class dma_fifo_core_3000 : boost::noncopyable +{ +public: +    typedef boost::shared_ptr<dma_fifo_core_3000> sptr; +    virtual ~dma_fifo_core_3000(void) = 0; + +    /*! +     * Create a DMA FIFO controller using the given bus, settings and readback base +     * Throws uhd::runtime_error if a DMA FIFO is not instantiated in the FPGA +     */ +    static sptr make(uhd::wb_iface::sptr iface, const size_t set_base, const size_t rb_addr); + +    /*! +     * Check if a DMA FIFO is instantiated in the FPGA +     */ +    static bool check(uhd::wb_iface::sptr iface, const size_t set_base, const size_t rb_addr); + +    /*! +     * Flush the DMA FIFO. Will clear all contents. +     */ +    virtual void flush() = 0; + +    /*! +     * Resize and rebase the DMA FIFO. Will clear all contents. +     */ +    virtual void resize(const boost::uint32_t base_addr, const boost::uint32_t size) = 0; + +    /*! +     * Get the (approx) number of bytes currently in the DMA FIFO +     */ +    virtual boost::uint32_t get_bytes_occupied() = 0; + +    /*! +     * Run the built-in-self-test routine for the DMA FIFO +     */ +    virtual boost::uint8_t run_bist(bool finite = true, boost::uint32_t timeout_ms = 500) = 0; + +    /*! +     * Is extended BIST supported +     */ +    virtual bool ext_bist_supported() = 0; + +    /*! +     * Run the built-in-self-test routine for the DMA FIFO (extended BIST only) +     */ +    virtual boost::uint8_t run_ext_bist( +        bool finite, +        boost::uint32_t rx_samp_delay, +        boost::uint32_t tx_pkt_delay, +        boost::uint32_t sid, +        boost::uint32_t timeout_ms = 500) = 0; + +    /*! +     * Get the throughput measured from the last invocation of the BIST (extended BIST only) +     */ +    virtual double get_bist_throughput(double fifo_clock_rate) = 0; + +}; + +#endif /* INCLUDED_LIBUHD_USRP_DMA_FIFO_CORE_3000_HPP */ diff --git a/host/lib/usrp/cores/gpio_atr_3000.cpp b/host/lib/usrp/cores/gpio_atr_3000.cpp new file mode 100644 index 000000000..3e0aa1f03 --- /dev/null +++ b/host/lib/usrp/cores/gpio_atr_3000.cpp @@ -0,0 +1,297 @@ +// +// Copyright 2011,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 "gpio_atr_3000.hpp" +#include <uhd/types/dict.hpp> +#include <uhd/utils/soft_register.hpp> + +using namespace uhd; +using namespace usrp; + +//------------------------------------------------------------- +// gpio_atr_3000 +//------------------------------------------------------------- + +#define REG_ATR_IDLE_OFFSET     (base + 0) +#define REG_ATR_RX_OFFSET       (base + 4) +#define REG_ATR_TX_OFFSET       (base + 8) +#define REG_ATR_FDX_OFFSET      (base + 12) +#define REG_DDR_OFFSET          (base + 16) +#define REG_ATR_DISABLE_OFFSET  (base + 20) + +namespace uhd { namespace usrp { namespace gpio_atr { + +class gpio_atr_3000_impl : public gpio_atr_3000{ +public: +    gpio_atr_3000_impl( +        wb_iface::sptr iface, +        const wb_iface::wb_addr_type base, +        const wb_iface::wb_addr_type rb_addr = READBACK_DISABLED +    ): +        _iface(iface), _rb_addr(rb_addr), +        _atr_idle_reg(REG_ATR_IDLE_OFFSET, _atr_disable_reg), +        _atr_rx_reg(REG_ATR_RX_OFFSET), +        _atr_tx_reg(REG_ATR_TX_OFFSET), +        _atr_fdx_reg(REG_ATR_FDX_OFFSET), +        _ddr_reg(REG_DDR_OFFSET), +        _atr_disable_reg(REG_ATR_DISABLE_OFFSET) +    { +        _atr_idle_reg.initialize(*_iface, true); +        _atr_rx_reg.initialize(*_iface, true); +        _atr_tx_reg.initialize(*_iface, true); +        _atr_fdx_reg.initialize(*_iface, true); +        _ddr_reg.initialize(*_iface, true); +        _atr_disable_reg.initialize(*_iface, true); +    } + +    virtual void set_atr_mode(const gpio_atr_mode_t mode, const boost::uint32_t mask) +    { +        //Each bit in the "ATR Disable" register determines whether the respective bit in the GPIO +        //output bus is driven by the ATR engine or a static register. +        //For each bit position, a 1 means that the bit is static and 0 means that the bit +        //is driven by the ATR state machine. +        //This setting will only get applied to all bits in the "mask" that are 1. All other +        //bits will retain their old value. +        _atr_disable_reg.set_with_mask((mode==MODE_ATR) ? ~MASK_SET_ALL : MASK_SET_ALL, mask); +        _atr_disable_reg.flush(); +    } + +    virtual void set_gpio_ddr(const gpio_ddr_t dir, const boost::uint32_t mask) +    { +        //Each bit in the "DDR" register determines whether the respective bit in the GPIO +        //bus is an input or an output. +        //For each bit position, a 1 means that the bit is an output and 0 means that the bit +        //is an input. +        //This setting will only get applied to all bits in the "mask" that are 1. All other +        //bits will retain their old value. +        _ddr_reg.set_with_mask((dir==DDR_INPUT) ? ~MASK_SET_ALL : MASK_SET_ALL, mask); +        _ddr_reg.flush(); +    } + +    virtual void set_atr_reg(const gpio_atr_reg_t atr, const boost::uint32_t value, const boost::uint32_t mask = MASK_SET_ALL) +    { +        //Set the value of the specified ATR register. For bits with ATR Disable set to 1, +        //the IDLE register will hold the output state +        //This setting will only get applied to all bits in the "mask" that are 1. All other +        //bits will retain their old value. +        masked_reg_t* reg = NULL; +        switch (atr) { +            case ATR_REG_IDLE:          reg = &_atr_idle_reg; break; +            case ATR_REG_RX_ONLY:       reg = &_atr_rx_reg;   break; +            case ATR_REG_TX_ONLY:       reg = &_atr_tx_reg;   break; +            case ATR_REG_FULL_DUPLEX:   reg = &_atr_fdx_reg;  break; +            default:                    reg = &_atr_idle_reg; break; +        } +        //For protection we only write to bits that have the mode ATR by masking the user +        //specified "mask" with ~atr_disable. +        reg->set_with_mask(value, mask); +        reg->flush(); +    } + +    virtual void set_gpio_out(const boost::uint32_t value, const boost::uint32_t mask = MASK_SET_ALL) { +        //Set the value of the specified GPIO output register. +        //This setting will only get applied to all bits in the "mask" that are 1. All other +        //bits will retain their old value. + +        //For protection we only write to bits that have the mode GPIO by masking the user +        //specified "mask" with atr_disable. +        _atr_idle_reg.set_gpio_out_with_mask(value, mask); +        _atr_idle_reg.flush(); +    } + +    virtual boost::uint32_t read_gpio() +    { +        //Read the state of the GPIO pins +        //If a pin is configured as an input, reads the actual value of the pin +        //If a pin is configured as an output, reads the last value written to the pin +        if (_rb_addr != READBACK_DISABLED) { +            return _iface->peek32(_rb_addr); +        } else { +            throw uhd::runtime_error("read_gpio not supported for write-only interface."); +        } +    } + +    inline virtual void set_gpio_attr(const gpio_attr_t attr, const boost::uint32_t value) +    { +        //An attribute based API to configure all settings for the GPIO bus in one function +        //call. This API does not have a mask so it configures all bits at the same time. +        switch (attr) +        { +        case GPIO_CTRL: +            set_atr_mode(MODE_ATR, value);   //Configure mode=ATR for all bits that are set +            set_atr_mode(MODE_GPIO, ~value); //Configure mode=GPIO for all bits that are unset +            break; +        case GPIO_DDR: +            set_gpio_ddr(DDR_OUTPUT, value); //Configure as output for all bits that are set +            set_gpio_ddr(DDR_INPUT, ~value); //Configure as input for all bits that are unset +            break; +        case GPIO_OUT: +            //Only set bits that are driven statically +            set_gpio_out(value); +            break; +        case GPIO_ATR_0X: +            //Only set bits that are driven by the ATR engine +            set_atr_reg(ATR_REG_IDLE, value); +            break; +        case GPIO_ATR_RX: +            //Only set bits that are driven by the ATR engine +            set_atr_reg(ATR_REG_RX_ONLY, value); +            break; +        case GPIO_ATR_TX: +            //Only set bits that are driven by the ATR engine +            set_atr_reg(ATR_REG_TX_ONLY, value); +            break; +        case GPIO_ATR_XX: +            //Only set bits that are driven by the ATR engine +            set_atr_reg(ATR_REG_FULL_DUPLEX, value); +            break; +        default: +            UHD_THROW_INVALID_CODE_PATH(); +        } +    } + +private: +    //Special RB addr value to indicate no readback +    //This value is invalid as a real address because it is not a multiple of 4 +    static const wb_iface::wb_addr_type READBACK_DISABLED = 0xFFFFFFFF; + +    class masked_reg_t : public uhd::soft_reg32_wo_t { +    public: +        masked_reg_t(const wb_iface::wb_addr_type offset): uhd::soft_reg32_wo_t(offset) { +            set(REGISTER, 0); +        } + +        virtual void set_with_mask(const boost::uint32_t value, const boost::uint32_t mask) { +            set(REGISTER, (value&mask)|(get(REGISTER)&(~mask))); +        } + +        virtual void flush() { +            uhd::soft_reg32_wo_t::flush(); +        } +    }; + +    class atr_idle_reg_t : public masked_reg_t { +    public: +        atr_idle_reg_t(const wb_iface::wb_addr_type offset, masked_reg_t& atr_disable_reg): +            masked_reg_t(offset), +            _atr_idle_cache(0), _gpio_out_cache(0), +            _atr_disable_reg(atr_disable_reg) +        { } + +        virtual void set_with_mask(const boost::uint32_t value, const boost::uint32_t mask) { +            _atr_idle_cache = (value&mask)|(_atr_idle_cache&(~mask)); +        } + +        void set_gpio_out_with_mask(const boost::uint32_t value, const boost::uint32_t mask) { +            _gpio_out_cache = (value&mask)|(_gpio_out_cache&(~mask)); +        } + +        virtual void flush() { +            set(REGISTER, +                (_atr_idle_cache & (~_atr_disable_reg.get(REGISTER))) | +                (_gpio_out_cache & _atr_disable_reg.get(REGISTER)) +            ); +            masked_reg_t::flush(); +        } + +    private: +        boost::uint32_t _atr_idle_cache; +        boost::uint32_t _gpio_out_cache; +        masked_reg_t&   _atr_disable_reg; +    }; + +    wb_iface::sptr          _iface; +    wb_iface::wb_addr_type  _rb_addr; +    atr_idle_reg_t          _atr_idle_reg; +    masked_reg_t            _atr_rx_reg; +    masked_reg_t            _atr_tx_reg; +    masked_reg_t            _atr_fdx_reg; +    masked_reg_t            _ddr_reg; +    masked_reg_t            _atr_disable_reg; +}; + +gpio_atr_3000::sptr gpio_atr_3000::make( +    wb_iface::sptr iface, const wb_iface::wb_addr_type base, const wb_iface::wb_addr_type rb_addr +) { +    return sptr(new gpio_atr_3000_impl(iface, base, rb_addr)); +} + +gpio_atr_3000::sptr gpio_atr_3000::make_write_only( +    wb_iface::sptr iface, const wb_iface::wb_addr_type base +) { +    gpio_atr_3000::sptr gpio_iface(new gpio_atr_3000_impl(iface, base)); +    gpio_iface->set_gpio_ddr(DDR_OUTPUT, MASK_SET_ALL); +    return gpio_iface; +} + +//------------------------------------------------------------- +// db_gpio_atr_3000 +//------------------------------------------------------------- + +class db_gpio_atr_3000_impl : public gpio_atr_3000_impl, public db_gpio_atr_3000 { +public: +    db_gpio_atr_3000_impl(wb_iface::sptr iface, const wb_iface::wb_addr_type base, const wb_iface::wb_addr_type rb_addr): +        gpio_atr_3000_impl(iface, base, rb_addr) { /* NOP */ } + +    inline void set_pin_ctrl(const db_unit_t unit, const boost::uint16_t value) +    { +        gpio_atr_3000_impl::set_atr_mode(MODE_ATR,  compute_mask(unit, value)); +        gpio_atr_3000_impl::set_atr_mode(MODE_GPIO, compute_mask(unit, ~value)); +    } + +    inline void set_gpio_ddr(const db_unit_t unit, const boost::uint16_t value) +    { +        gpio_atr_3000_impl::set_gpio_ddr(DDR_OUTPUT, compute_mask(unit, value)); +        gpio_atr_3000_impl::set_gpio_ddr(DDR_INPUT,  compute_mask(unit, ~value)); +    } + +    inline void set_atr_reg(const db_unit_t unit, const gpio_atr_reg_t atr, const boost::uint16_t value) +    { +        gpio_atr_3000_impl::set_atr_reg(atr, +            static_cast<boost::uint32_t>(value) << compute_shift(unit), +            compute_mask(unit, 0xFFFF)); +    } + +    inline void set_gpio_out(const db_unit_t unit, const boost::uint16_t value) +    { +        gpio_atr_3000_impl::set_gpio_out( +            static_cast<boost::uint32_t>(value) << compute_shift(unit), +            compute_mask(unit, 0xFFFF)); +    } + +    inline boost::uint16_t read_gpio(const db_unit_t unit) +    { +        return boost::uint16_t(gpio_atr_3000_impl::read_gpio() >> compute_shift(unit)); +    } + +private: +    inline boost::uint32_t compute_shift(const db_unit_t unit) { +        return (unit == dboard_iface::UNIT_RX) ? 0 : 16; +    } + +    inline boost::uint32_t compute_mask(const db_unit_t unit, const boost::uint16_t mask) { +        return static_cast<boost::uint32_t>(mask) << (compute_shift(unit)); +    } +}; + +db_gpio_atr_3000::sptr db_gpio_atr_3000::make( +    wb_iface::sptr iface, const wb_iface::wb_addr_type base, const wb_iface::wb_addr_type rb_addr +) { +    return sptr(new db_gpio_atr_3000_impl(iface, base, rb_addr)); +} + +}}} diff --git a/host/lib/usrp/cores/gpio_atr_3000.hpp b/host/lib/usrp/cores/gpio_atr_3000.hpp new file mode 100644 index 000000000..b30cd3b85 --- /dev/null +++ b/host/lib/usrp/cores/gpio_atr_3000.hpp @@ -0,0 +1,175 @@ +// +// Copyright 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 +// 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_LIBUHD_USRP_GPIO_CORE_3000_HPP +#define INCLUDED_LIBUHD_USRP_GPIO_CORE_3000_HPP + +#include <uhd/config.hpp> +#include <uhd/usrp/dboard_iface.hpp> +#include <uhd/usrp/gpio_defs.hpp> +#include <boost/shared_ptr.hpp> +#include <uhd/types/wb_iface.hpp> + +namespace uhd { namespace usrp { namespace gpio_atr { + +class gpio_atr_3000 : boost::noncopyable { +public: +    typedef boost::shared_ptr<gpio_atr_3000> sptr; + +    static const boost::uint32_t MASK_SET_ALL = 0xFFFFFFFF; + +    virtual ~gpio_atr_3000(void) {}; + +    /*! +     * Create a read-write GPIO ATR interface object +     * +     * \param iface register iface to GPIO ATR registers +     * \param base base settings offset for GPIO ATR registers +     * \param base readback offset for GPIO ATR registers +     */ +    static sptr make( +        uhd::wb_iface::sptr iface, +        const uhd::wb_iface::wb_addr_type base, +        const uhd::wb_iface::wb_addr_type rb_addr); + +    /*! +     * Create a write-only GPIO ATR interface object +     * +     * \param iface register iface to GPIO ATR registers +     * \param base base settings offset for GPIO ATR registers +     */ +    static sptr make_write_only( +        uhd::wb_iface::sptr iface, const uhd::wb_iface::wb_addr_type base); + +    /*! +     * Select the ATR mode for all bits in the mask +     * +     * \param mode the mode to apply {ATR = outputs driven by ATR state machine, GPIO = outputs static} +     * \param mask apply the mode to all non-zero bits in the mask +     */ +    virtual void set_atr_mode(const gpio_atr_mode_t mode, const boost::uint32_t mask) = 0; + +    /*! +     * Select the data direction for all bits in the mask +     * +     * \param dir the direction {OUTPUT, INPUT} +     * \param mask apply the mode to all non-zero bits in the mask +     */ +    virtual void set_gpio_ddr(const gpio_ddr_t dir, const boost::uint32_t mask) = 0; + +    /*! +     * Write the specified (masked) value to the ATR register +     * +     * \param atr the type of ATR register to write to {IDLE, RX, TX, FDX} +     * \param value the value to write +     * \param mask only writes to the bits where mask is non-zero +     */ +    virtual void set_atr_reg(const gpio_atr_reg_t atr, const boost::uint32_t value, const boost::uint32_t mask = MASK_SET_ALL) = 0; + +    /*! +     * Write to a static GPIO output +     * +     * \param value the value to write +     * \param mask only writes to the bits where mask is non-zero +     */ +    virtual void set_gpio_out(const boost::uint32_t value, const boost::uint32_t mask = MASK_SET_ALL) = 0; + +    /*! +     * Read the state of the GPIO pins +     * If a pin is configured as an input, reads the actual value of the pin +     * If a pin is configured as an output, reads the last value written to the pin +     * +     * \return the value read back +     */ +    virtual boost::uint32_t read_gpio() = 0; + +    /*! +     * Set a GPIO attribute +     * +     * \param attr the attribute to set +     * \param value the value to write to the attribute +     */ +    virtual void set_gpio_attr(const gpio_attr_t attr, const boost::uint32_t value) = 0; +}; + +class db_gpio_atr_3000 { +public: +    typedef boost::shared_ptr<db_gpio_atr_3000> sptr; + +    typedef uhd::usrp::dboard_iface::unit_t db_unit_t; + +    virtual ~db_gpio_atr_3000(void) {}; + +    /*! +     * Create a read-write GPIO ATR interface object for a daughterboard connector +     * +     * \param iface register iface to GPIO ATR registers +     * \param base base settings offset for GPIO ATR registers +     * \param base readback offset for GPIO ATR registers +     */ +    static sptr make( +        uhd::wb_iface::sptr iface, +        const uhd::wb_iface::wb_addr_type base, +        const uhd::wb_iface::wb_addr_type rb_addr); + +    /*! +     * Configure the GPIO mode for all pins in the daughterboard connector +     * +     * \param unit the side of the daughterboard interface to configure (TX or RX) +     * \param value if value[i] is 1, the i'th bit is in ATR mode otherwise it is in GPIO mode +     */ +    virtual void set_pin_ctrl(const db_unit_t unit, const boost::uint16_t value) = 0; + +    /*! +     * Configure the direction for all pins in the daughterboard connector +     * +     * \param unit the side of the daughterboard interface to configure (TX or RX) +     * \param value if value[i] is 1, the i'th bit is an output otherwise it is an input +     */ +    virtual void set_gpio_ddr(const db_unit_t unit, const boost::uint16_t value) = 0; + +    /*! +     * Write the specified value to the ATR register (all bits) +     * +     * \param atr the type of ATR register to write to {IDLE, RX, TX, FDX} +     * \param unit the side of the daughterboard interface to configure (TX or RX) +     * \param value the value to write +     */ +    virtual void set_atr_reg(const db_unit_t unit, const gpio_atr_reg_t atr, const boost::uint16_t value) = 0; + +    /*! +     * Write the specified value to the GPIO register (all bits) +     * +     * \param atr the type of ATR register to write to {IDLE, RX, TX, FDX} +     * \param value the value to write +     */ +    virtual void set_gpio_out(const db_unit_t unit, const boost::uint16_t value) = 0; + +    /*! +     * Read the state of the GPIO pins +     * If a pin is configured as an input, reads the actual value of the pin +     * If a pin is configured as an output, reads the last value written to the pin +     * +     * \param unit the side of the daughterboard interface to configure (TX or RX) +     * \return the value read back +     */ +    virtual boost::uint16_t read_gpio(const db_unit_t unit) = 0; +}; + +}}} //namespaces + +#endif /* INCLUDED_LIBUHD_USRP_GPIO_CORE_3000_HPP */ diff --git a/host/lib/usrp/cores/gpio_core_200.cpp b/host/lib/usrp/cores/gpio_core_200.cpp index 4f1c25a0b..05a689845 100644 --- a/host/lib/usrp/cores/gpio_core_200.cpp +++ b/host/lib/usrp/cores/gpio_core_200.cpp @@ -77,10 +77,10 @@ private:      }      void update(void){ -        this->update(dboard_iface::ATR_REG_IDLE, REG_GPIO_IDLE); -        this->update(dboard_iface::ATR_REG_TX_ONLY, REG_GPIO_TX_ONLY); -        this->update(dboard_iface::ATR_REG_RX_ONLY, REG_GPIO_RX_ONLY); -        this->update(dboard_iface::ATR_REG_FULL_DUPLEX, REG_GPIO_BOTH); +        this->update(gpio_atr::ATR_REG_IDLE, REG_GPIO_IDLE); +        this->update(gpio_atr::ATR_REG_TX_ONLY, REG_GPIO_TX_ONLY); +        this->update(gpio_atr::ATR_REG_RX_ONLY, REG_GPIO_RX_ONLY); +        this->update(gpio_atr::ATR_REG_FULL_DUPLEX, REG_GPIO_BOTH);      }      void update(const atr_reg_t atr, const size_t addr){ @@ -122,17 +122,17 @@ public:      }      void set_atr_reg(const atr_reg_t atr, const boost::uint32_t value){ -        if (atr == dboard_iface::ATR_REG_IDLE)        _iface->poke32(REG_GPIO_IDLE, value); -        if (atr == dboard_iface::ATR_REG_TX_ONLY)     _iface->poke32(REG_GPIO_TX_ONLY, value); -        if (atr == dboard_iface::ATR_REG_RX_ONLY)     _iface->poke32(REG_GPIO_RX_ONLY, value); -        if (atr == dboard_iface::ATR_REG_FULL_DUPLEX) _iface->poke32(REG_GPIO_BOTH, value); +        if (atr == gpio_atr::ATR_REG_IDLE)        _iface->poke32(REG_GPIO_IDLE, value); +        if (atr == gpio_atr::ATR_REG_TX_ONLY)     _iface->poke32(REG_GPIO_TX_ONLY, value); +        if (atr == gpio_atr::ATR_REG_RX_ONLY)     _iface->poke32(REG_GPIO_RX_ONLY, value); +        if (atr == gpio_atr::ATR_REG_FULL_DUPLEX) _iface->poke32(REG_GPIO_BOTH, value);      }      void set_all_regs(const boost::uint32_t value){ -        this->set_atr_reg(dboard_iface::ATR_REG_IDLE,        value); -        this->set_atr_reg(dboard_iface::ATR_REG_TX_ONLY,     value); -        this->set_atr_reg(dboard_iface::ATR_REG_RX_ONLY,     value); -        this->set_atr_reg(dboard_iface::ATR_REG_FULL_DUPLEX, value); +        this->set_atr_reg(gpio_atr::ATR_REG_IDLE,        value); +        this->set_atr_reg(gpio_atr::ATR_REG_TX_ONLY,     value); +        this->set_atr_reg(gpio_atr::ATR_REG_RX_ONLY,     value); +        this->set_atr_reg(gpio_atr::ATR_REG_FULL_DUPLEX, value);      }  private: diff --git a/host/lib/usrp/cores/gpio_core_200.hpp b/host/lib/usrp/cores/gpio_core_200.hpp index e22834fd9..c60507792 100644 --- a/host/lib/usrp/cores/gpio_core_200.hpp +++ b/host/lib/usrp/cores/gpio_core_200.hpp @@ -20,6 +20,7 @@  #include <uhd/config.hpp>  #include <uhd/usrp/dboard_iface.hpp> +#include <uhd/usrp/gpio_defs.hpp>  #include <boost/assign.hpp>  #include <boost/cstdint.hpp>  #include <boost/utility.hpp> @@ -27,28 +28,6 @@  #include <uhd/types/wb_iface.hpp>  #include <map> -typedef enum { -    GPIO_CTRL, -    GPIO_DDR, -    GPIO_OUT, -    GPIO_ATR_0X, -    GPIO_ATR_RX, -    GPIO_ATR_TX, -    GPIO_ATR_XX -} gpio_attr_t; - -typedef std::map<gpio_attr_t,std::string> gpio_attr_map_t; -static const gpio_attr_map_t gpio_attr_map = -    boost::assign::map_list_of -        (GPIO_CTRL,   "CTRL") -        (GPIO_DDR,    "DDR") -        (GPIO_OUT,    "OUT") -        (GPIO_ATR_0X, "ATR_0X") -        (GPIO_ATR_RX, "ATR_RX") -        (GPIO_ATR_TX, "ATR_TX") -        (GPIO_ATR_XX, "ATR_XX") -; -  class gpio_core_200 : boost::noncopyable{  public:      typedef boost::shared_ptr<gpio_core_200> sptr; diff --git a/host/lib/usrp/cores/tx_vita_core_3000.cpp b/host/lib/usrp/cores/tx_vita_core_3000.cpp index 71a2b7e21..c76b384d9 100644 --- a/host/lib/usrp/cores/tx_vita_core_3000.cpp +++ b/host/lib/usrp/cores/tx_vita_core_3000.cpp @@ -18,9 +18,11 @@  #include "tx_vita_core_3000.hpp"  #include <uhd/utils/safe_call.hpp> -#define REG_CTRL_ERROR_POLICY           _base + 0 -#define REG_DEFRAMER_CYCLE_FC_UPS       _base + 2*4 + 0 -#define REG_DEFRAMER_PACKET_FC_UPS      _base + 2*4 + 4 +#define REG_CTRL_ERROR_POLICY       (_base + 0) +#define REG_FC_PRE_RADIO_RESP_BASE  (_base + 2*4) +#define REG_FC_PRE_FIFO_RESP_BASE   (_base + 4*4) +#define REG_CTRL_FC_CYCLE_OFFSET    (0*4) +#define REG_CTRL_FC_PACKET_OFFSET   (1*4)  using namespace uhd; @@ -32,12 +34,22 @@ struct tx_vita_core_3000_impl : tx_vita_core_3000  {      tx_vita_core_3000_impl(          wb_iface::sptr iface, -        const size_t base +        const size_t base, +        fc_monitor_loc fc_location      ):          _iface(iface), -        _base(base) +        _base(base), +        _fc_base((fc_location==FC_PRE_RADIO or fc_location==FC_DEFAULT) ? +                    REG_FC_PRE_RADIO_RESP_BASE : REG_FC_PRE_FIFO_RESP_BASE), +        _fc_location(fc_location)      { -        this->set_tick_rate(1); //init to non zero +        if (fc_location != FC_DEFAULT) { +            //Turn off the other FC monitoring module +            const size_t other_fc_base = (fc_location==FC_PRE_RADIO) ? +                    REG_FC_PRE_FIFO_RESP_BASE : REG_FC_PRE_RADIO_RESP_BASE; +            _iface->poke32(other_fc_base + REG_CTRL_FC_CYCLE_OFFSET, 0); +            _iface->poke32(other_fc_base + REG_CTRL_FC_PACKET_OFFSET, 0); +        }          this->set_underflow_policy("next_packet");          this->clear();      } @@ -56,11 +68,6 @@ struct tx_vita_core_3000_impl : tx_vita_core_3000          this->set_underflow_policy(_policy); //clears the seq      } -    void set_tick_rate(const double rate) -    { -        _tick_rate = rate; -    } -      void set_underflow_policy(const std::string &policy)      {          if (policy == "next_packet") @@ -89,23 +96,35 @@ struct tx_vita_core_3000_impl : tx_vita_core_3000      void configure_flow_control(const size_t cycs_per_up, const size_t pkts_per_up)      { -        if (cycs_per_up == 0) _iface->poke32(REG_DEFRAMER_CYCLE_FC_UPS, 0); -        else _iface->poke32(REG_DEFRAMER_CYCLE_FC_UPS, (1 << 31) | ((cycs_per_up) & 0xffffff)); +        if (cycs_per_up == 0) _iface->poke32(_fc_base + REG_CTRL_FC_CYCLE_OFFSET, 0); +        else _iface->poke32(_fc_base + REG_CTRL_FC_CYCLE_OFFSET, (1 << 31) | ((cycs_per_up) & 0xffffff)); -        if (pkts_per_up == 0) _iface->poke32(REG_DEFRAMER_PACKET_FC_UPS, 0); -        else _iface->poke32(REG_DEFRAMER_PACKET_FC_UPS, (1 << 31) | ((pkts_per_up) & 0xffff)); +        if (pkts_per_up == 0) _iface->poke32(_fc_base + REG_CTRL_FC_PACKET_OFFSET, 0); +        else _iface->poke32(_fc_base + REG_CTRL_FC_PACKET_OFFSET, (1 << 31) | ((pkts_per_up) & 0xffff));      } -    wb_iface::sptr _iface; -    const size_t _base; -    double _tick_rate; -    std::string _policy; +    wb_iface::sptr  _iface; +    const size_t    _base; +    const size_t    _fc_base; +    std::string     _policy; +    fc_monitor_loc  _fc_location; +  };  tx_vita_core_3000::sptr tx_vita_core_3000::make(      wb_iface::sptr iface, +    const size_t base, +    fc_monitor_loc fc_location +) +{ +    return tx_vita_core_3000::sptr(new tx_vita_core_3000_impl(iface, base, fc_location)); +} + +tx_vita_core_3000::sptr tx_vita_core_3000::make_no_radio_buff( +    wb_iface::sptr iface,      const size_t base  )  { -    return tx_vita_core_3000::sptr(new tx_vita_core_3000_impl(iface, base)); +    //No internal radio buffer so only pre-radio monitoring is supported. +    return tx_vita_core_3000::sptr(new tx_vita_core_3000_impl(iface, base, FC_DEFAULT));  } diff --git a/host/lib/usrp/cores/tx_vita_core_3000.hpp b/host/lib/usrp/cores/tx_vita_core_3000.hpp index 4c0052d4f..bd0f20ba4 100644 --- a/host/lib/usrp/cores/tx_vita_core_3000.hpp +++ b/host/lib/usrp/cores/tx_vita_core_3000.hpp @@ -32,17 +32,27 @@ class tx_vita_core_3000 : boost::noncopyable  public:      typedef boost::shared_ptr<tx_vita_core_3000> sptr; +    enum fc_monitor_loc { +        FC_DEFAULT, +        FC_PRE_RADIO, +        FC_PRE_FIFO +    }; +      virtual ~tx_vita_core_3000(void) = 0;      static sptr make(          uhd::wb_iface::sptr iface, +        const size_t base, +        fc_monitor_loc fc_location = FC_PRE_RADIO +    ); + +    static sptr make_no_radio_buff( +        uhd::wb_iface::sptr iface,          const size_t base      );      virtual void clear(void) = 0; -    virtual void set_tick_rate(const double rate) = 0; -      virtual void setup(const uhd::stream_args_t &stream_args) = 0;      virtual void configure_flow_control(const size_t cycs_per_up, const size_t pkts_per_up) = 0; diff --git a/host/lib/usrp/dboard/db_rfx.cpp b/host/lib/usrp/dboard/db_rfx.cpp index 1342c913d..3e7df9a39 100644 --- a/host/lib/usrp/dboard/db_rfx.cpp +++ b/host/lib/usrp/dboard/db_rfx.cpp @@ -248,15 +248,15 @@ rfx_xcvr::rfx_xcvr(      this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, output_enables);      //setup the tx atr (this does not change with antenna) -    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_IDLE,        _power_up | ANT_XX | MIXER_DIS); -    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_RX_ONLY,     _power_up | ANT_RX | MIXER_DIS); -    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_TX_ONLY,     _power_up | ANT_TX | MIXER_ENB); -    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_FULL_DUPLEX, _power_up | ANT_TX | MIXER_ENB); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_IDLE,        _power_up | ANT_XX | MIXER_DIS); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_RX_ONLY,     _power_up | ANT_RX | MIXER_DIS); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_TX_ONLY,     _power_up | ANT_TX | MIXER_ENB); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_FULL_DUPLEX, _power_up | ANT_TX | MIXER_ENB);      //setup the rx atr (this does not change with antenna) -    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE,        _power_up | ANT_XX | MIXER_DIS); -    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY,     _power_up | ANT_XX | MIXER_DIS); -    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, _power_up | ANT_RX2| MIXER_ENB); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_IDLE,        _power_up | ANT_XX | MIXER_DIS); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_TX_ONLY,     _power_up | ANT_XX | MIXER_DIS); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_FULL_DUPLEX, _power_up | ANT_RX2| MIXER_ENB);  }  rfx_xcvr::~rfx_xcvr(void){ @@ -272,14 +272,14 @@ void rfx_xcvr::set_rx_ant(const std::string &ant){      //set the rx atr regs that change with antenna setting      if (ant == "CAL") { -        this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY,     _power_up | ANT_TXRX  | MIXER_ENB); -        this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, _power_up | ANT_TXRX  | MIXER_ENB); -        this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY,     _power_up | MIXER_ENB | ANT_TXRX ); +        this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_TX_ONLY,     _power_up | ANT_TXRX  | MIXER_ENB); +        this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_FULL_DUPLEX, _power_up | ANT_TXRX  | MIXER_ENB); +        this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_RX_ONLY,     _power_up | MIXER_ENB | ANT_TXRX );      }       else { -        this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY,     _power_up | ANT_XX | MIXER_DIS); -        this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, _power_up | ANT_RX2| MIXER_ENB); -        this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY,     _power_up | MIXER_ENB | +        this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_TX_ONLY,     _power_up | ANT_XX | MIXER_DIS); +        this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_FULL_DUPLEX, _power_up | ANT_RX2| MIXER_ENB); +        this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_RX_ONLY,     _power_up | MIXER_ENB |              ((ant == "TX/RX")? ANT_TXRX : ANT_RX2));      } @@ -292,12 +292,12 @@ void rfx_xcvr::set_tx_ant(const std::string &ant){      //set the tx atr regs that change with antenna setting      if (ant == "CAL") { -        this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_TX_ONLY,     _power_up | ANT_RX | MIXER_ENB); -        this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_FULL_DUPLEX, _power_up | ANT_RX | MIXER_ENB); +        this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_TX_ONLY,     _power_up | ANT_RX | MIXER_ENB); +        this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_FULL_DUPLEX, _power_up | ANT_RX | MIXER_ENB);      }       else { -        this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_TX_ONLY,     _power_up | ANT_TX | MIXER_ENB); -        this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_FULL_DUPLEX, _power_up | ANT_TX | MIXER_ENB); +        this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_TX_ONLY,     _power_up | ANT_TX | MIXER_ENB); +        this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_FULL_DUPLEX, _power_up | ANT_TX | MIXER_ENB);      }  } diff --git a/host/lib/usrp/dboard/db_sbx_common.cpp b/host/lib/usrp/dboard/db_sbx_common.cpp index ce5166c4c..c575bba01 100644 --- a/host/lib/usrp/dboard/db_sbx_common.cpp +++ b/host/lib/usrp/dboard/db_sbx_common.cpp @@ -237,8 +237,8 @@ sbx_xcvr::sbx_xcvr(ctor_args_t args) : xcvr_dboard_base(args){      this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, (TXIO_MASK|TX_LED_IO));      this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, (RXIO_MASK|RX_LED_IO)); -    //flash LEDs -    flash_leds(); +    //Initialize ATR registers after direction and pin ctrl configuration +    update_atr();      UHD_LOGV(often) << boost::format(          "SBX GPIO Direction: RX: 0x%08x, TX: 0x%08x" @@ -265,39 +265,39 @@ void sbx_xcvr::update_atr(void){      //setup the tx atr (this does not change with antenna)      this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, \ -            dboard_iface::ATR_REG_IDLE, 0 | tx_lo_lpf_en \ +            gpio_atr::ATR_REG_IDLE, 0 | tx_lo_lpf_en \              | tx_ld_led | tx_ant_led | TX_POWER_UP | ANT_XX | TX_MIXER_DIS);      //setup the rx atr (this does not change with antenna)      this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, \ -            dboard_iface::ATR_REG_IDLE, rx_pga0_iobits | rx_lo_lpf_en \ +            gpio_atr::ATR_REG_IDLE, rx_pga0_iobits | rx_lo_lpf_en \              | rx_ld_led | rx_ant_led | RX_POWER_UP | ANT_XX | RX_MIXER_DIS);      //set the RX atr regs that change with antenna setting      this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, \ -            dboard_iface::ATR_REG_RX_ONLY, rx_pga0_iobits | rx_lo_lpf_en \ +            gpio_atr::ATR_REG_RX_ONLY, rx_pga0_iobits | rx_lo_lpf_en \              | rx_ld_led | rx_ant_led | RX_POWER_UP | RX_MIXER_ENB \              | ((_rx_ant != "RX2")? ANT_TXRX : ANT_RX2));      this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, \ -            dboard_iface::ATR_REG_TX_ONLY, rx_pga0_iobits | rx_lo_lpf_en \ +            gpio_atr::ATR_REG_TX_ONLY, rx_pga0_iobits | rx_lo_lpf_en \              | rx_ld_led | rx_ant_led | RX_POWER_UP | RX_MIXER_DIS \              | ((_rx_ant == "CAL")? ANT_TXRX : ANT_RX2));      this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, \ -            dboard_iface::ATR_REG_FULL_DUPLEX, rx_pga0_iobits | rx_lo_lpf_en \ +            gpio_atr::ATR_REG_FULL_DUPLEX, rx_pga0_iobits | rx_lo_lpf_en \              | rx_ld_led | rx_ant_led | RX_POWER_UP | RX_MIXER_ENB \              | ((_rx_ant == "CAL")? ANT_TXRX : ANT_RX2));      //set the TX atr regs that change with antenna setting      this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, \ -            dboard_iface::ATR_REG_RX_ONLY, 0 | tx_lo_lpf_en \ +            gpio_atr::ATR_REG_RX_ONLY, 0 | tx_lo_lpf_en \              | tx_ld_led | tx_ant_led | TX_POWER_UP | TX_MIXER_DIS \              | ((_rx_ant != "RX2")? ANT_RX : ANT_TX));      this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, \ -            dboard_iface::ATR_REG_TX_ONLY, tx_pga0_iobits | tx_lo_lpf_en \ +            gpio_atr::ATR_REG_TX_ONLY, tx_pga0_iobits | tx_lo_lpf_en \              | tx_ld_led | tx_ant_led | TX_POWER_UP | TX_MIXER_ENB \              | ((_tx_ant == "CAL")? ANT_RX : ANT_TX));      this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, \ -            dboard_iface::ATR_REG_FULL_DUPLEX, tx_pga0_iobits | tx_lo_lpf_en \ +            gpio_atr::ATR_REG_FULL_DUPLEX, tx_pga0_iobits | tx_lo_lpf_en \              | tx_ld_led | tx_ant_led | TX_POWER_UP | TX_MIXER_ENB \              | ((_tx_ant == "CAL")? ANT_RX : ANT_TX));  } @@ -352,45 +352,3 @@ sensor_value_t sbx_xcvr::get_locked(dboard_iface::unit_t unit) {      return sensor_value_t("LO", locked, "locked", "unlocked");  } - - -void sbx_xcvr::flash_leds(void) { -    //Remove LED gpios from ATR control temporarily and set to outputs -    this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_TX, TXIO_MASK); -    this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, RXIO_MASK); -    this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, (TXIO_MASK|RX_LED_IO)); -    this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, (RXIO_MASK|RX_LED_IO)); - -    this->get_iface()->set_gpio_out(dboard_iface::UNIT_TX, TX_LED_LD, TX_LED_IO); -    boost::this_thread::sleep(boost::posix_time::milliseconds(100)); - -    this->get_iface()->set_gpio_out(dboard_iface::UNIT_TX, \ -            TX_LED_TXRX|TX_LED_LD, TX_LED_IO); -    boost::this_thread::sleep(boost::posix_time::milliseconds(100)); - -    this->get_iface()->set_gpio_out(dboard_iface::UNIT_RX, RX_LED_LD, RX_LED_IO); -    boost::this_thread::sleep(boost::posix_time::milliseconds(100)); - -    this->get_iface()->set_gpio_out(dboard_iface::UNIT_RX, \ -            RX_LED_RX1RX2|RX_LED_LD, RX_LED_IO); -    boost::this_thread::sleep(boost::posix_time::milliseconds(100)); - -    this->get_iface()->set_gpio_out(dboard_iface::UNIT_RX, RX_LED_LD, RX_LED_IO); -    boost::this_thread::sleep(boost::posix_time::milliseconds(100)); - -    this->get_iface()->set_gpio_out(dboard_iface::UNIT_RX, 0, RX_LED_IO); -    boost::this_thread::sleep(boost::posix_time::milliseconds(100)); - -    this->get_iface()->set_gpio_out(dboard_iface::UNIT_TX, TX_LED_LD, TX_LED_IO); -    boost::this_thread::sleep(boost::posix_time::milliseconds(100)); - -    this->get_iface()->set_gpio_out(dboard_iface::UNIT_TX, 0, TX_LED_IO); -    boost::this_thread::sleep(boost::posix_time::milliseconds(100)); - -    //Put LED gpios back in ATR control and update atr -    this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_TX, (TXIO_MASK|TX_LED_IO)); -    this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, (RXIO_MASK|RX_LED_IO)); -    this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, (TXIO_MASK|TX_LED_IO)); -    this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, (RXIO_MASK|RX_LED_IO)); -} - diff --git a/host/lib/usrp/dboard/db_ubx.cpp b/host/lib/usrp/dboard/db_ubx.cpp index 7cb4b2d6b..db9f21f43 100644 --- a/host/lib/usrp/dboard/db_ubx.cpp +++ b/host/lib/usrp/dboard/db_ubx.cpp @@ -26,6 +26,7 @@  #include <uhd/usrp/dboard_manager.hpp>  #include <uhd/utils/assert_has.hpp>  #include <uhd/utils/log.hpp> +#include <uhd/utils/msg.hpp>  #include <uhd/utils/static.hpp>  #include <boost/assign/list_of.hpp>  #include <boost/shared_ptr.hpp> @@ -318,14 +319,14 @@ public:          write_gpio();          // Configure ATR -        _iface->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_IDLE, _tx_gpio_reg.atr_idle); -        _iface->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_TX_ONLY, _tx_gpio_reg.atr_tx); -        _iface->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_RX_ONLY, _tx_gpio_reg.atr_rx); -        _iface->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_FULL_DUPLEX, _tx_gpio_reg.atr_full_duplex); -        _iface->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, _rx_gpio_reg.atr_idle); -        _iface->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY, _rx_gpio_reg.atr_tx); -        _iface->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY, _rx_gpio_reg.atr_rx); -        _iface->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, _rx_gpio_reg.atr_full_duplex); +        _iface->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_IDLE, _tx_gpio_reg.atr_idle); +        _iface->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_TX_ONLY, _tx_gpio_reg.atr_tx); +        _iface->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_RX_ONLY, _tx_gpio_reg.atr_rx); +        _iface->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_FULL_DUPLEX, _tx_gpio_reg.atr_full_duplex); +        _iface->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_IDLE, _rx_gpio_reg.atr_idle); +        _iface->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_TX_ONLY, _rx_gpio_reg.atr_tx); +        _iface->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_RX_ONLY, _rx_gpio_reg.atr_rx); +        _iface->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_FULL_DUPLEX, _rx_gpio_reg.atr_full_duplex);          // Engage ATR control (1 is ATR control, 0 is manual control)          _iface->set_pin_ctrl(dboard_iface::UNIT_TX, _tx_gpio_reg.atr_mask); @@ -683,6 +684,20 @@ private:          device_addr_t tune_args = subtree->access<device_addr_t>("tune_args").get();          is_int_n = boost::iequals(tune_args.get("mode_n",""), "integer");          UHD_LOGV(rarely) << boost::format("UBX TX: the requested frequency is %f MHz") % (freq/1e6) << std::endl; +        double target_pfd_freq = _tx_target_pfd_freq; +        if (is_int_n and tune_args.has_key("int_n_step")) +        { +            target_pfd_freq = tune_args.cast<double>("int_n_step", _tx_target_pfd_freq); +            if (target_pfd_freq > _tx_target_pfd_freq) +            { +                UHD_MSG(warning) +                    << boost::format("Requested int_n_step of %f MHz too large, clipping to %f MHz") +                    % (target_pfd_freq/1e6) +                    % (_tx_target_pfd_freq/1e6) +                    << std::endl; +                target_pfd_freq = _tx_target_pfd_freq; +            } +        }          // Clip the frequency to the valid range          freq = ubx_freq_range.clip(freq); @@ -704,10 +719,10 @@ private:              set_cpld_field(TXLB_SEL, 1);              set_cpld_field(TXHB_SEL, 0);              // Set LO1 to IF of 2100 MHz (offset from RX IF to reduce leakage) -            freq_lo1 = _txlo1->set_frequency(2100*fMHz, ref_freq, _tx_target_pfd_freq, is_int_n); +            freq_lo1 = _txlo1->set_frequency(2100*fMHz, ref_freq, target_pfd_freq, is_int_n);              _txlo1->set_output_power(max287x_iface::OUTPUT_POWER_5DBM);              // Set LO2 to IF minus desired frequency -            freq_lo2 = _txlo2->set_frequency(freq_lo1 - freq, ref_freq, _tx_target_pfd_freq, is_int_n); +            freq_lo2 = _txlo2->set_frequency(freq_lo1 - freq, ref_freq, target_pfd_freq, is_int_n);              _txlo2->set_output_power(max287x_iface::OUTPUT_POWER_2DBM);          }          else if ((freq >= (500*fMHz)) && (freq <= (800*fMHz))) @@ -717,7 +732,7 @@ private:              set_cpld_field(TXLO1_FSEL1, 1);              set_cpld_field(TXLB_SEL, 0);              set_cpld_field(TXHB_SEL, 1); -            freq_lo1 = _txlo1->set_frequency(freq, ref_freq, _tx_target_pfd_freq, is_int_n); +            freq_lo1 = _txlo1->set_frequency(freq, ref_freq, target_pfd_freq, is_int_n);              _txlo1->set_output_power(max287x_iface::OUTPUT_POWER_2DBM);          }          else if ((freq > (800*fMHz)) && (freq <= (1000*fMHz))) @@ -727,7 +742,7 @@ private:              set_cpld_field(TXLO1_FSEL1, 1);              set_cpld_field(TXLB_SEL, 0);              set_cpld_field(TXHB_SEL, 1); -            freq_lo1 = _txlo1->set_frequency(freq, ref_freq, _tx_target_pfd_freq, is_int_n); +            freq_lo1 = _txlo1->set_frequency(freq, ref_freq, target_pfd_freq, is_int_n);              _txlo1->set_output_power(max287x_iface::OUTPUT_POWER_5DBM);          }          else if ((freq > (1000*fMHz)) && (freq <= (2200*fMHz))) @@ -737,7 +752,7 @@ private:              set_cpld_field(TXLO1_FSEL1, 0);              set_cpld_field(TXLB_SEL, 0);              set_cpld_field(TXHB_SEL, 1); -            freq_lo1 = _txlo1->set_frequency(freq, ref_freq, _tx_target_pfd_freq, is_int_n); +            freq_lo1 = _txlo1->set_frequency(freq, ref_freq, target_pfd_freq, is_int_n);              _txlo1->set_output_power(max287x_iface::OUTPUT_POWER_2DBM);          }          else if ((freq > (2200*fMHz)) && (freq <= (2500*fMHz))) @@ -747,7 +762,7 @@ private:              set_cpld_field(TXLO1_FSEL1, 0);              set_cpld_field(TXLB_SEL, 0);              set_cpld_field(TXHB_SEL, 1); -            freq_lo1 = _txlo1->set_frequency(freq, ref_freq, _tx_target_pfd_freq, is_int_n); +            freq_lo1 = _txlo1->set_frequency(freq, ref_freq, target_pfd_freq, is_int_n);              _txlo1->set_output_power(max287x_iface::OUTPUT_POWER_2DBM);          }          else if ((freq > (2500*fMHz)) && (freq <= (6000*fMHz))) @@ -757,7 +772,7 @@ private:              set_cpld_field(TXLO1_FSEL1, 0);              set_cpld_field(TXLB_SEL, 0);              set_cpld_field(TXHB_SEL, 1); -            freq_lo1 = _txlo1->set_frequency(freq, ref_freq, _tx_target_pfd_freq, is_int_n); +            freq_lo1 = _txlo1->set_frequency(freq, ref_freq, target_pfd_freq, is_int_n);              _txlo1->set_output_power(max287x_iface::OUTPUT_POWER_5DBM);          } @@ -825,6 +840,20 @@ private:          property_tree::sptr subtree = this->get_rx_subtree();          device_addr_t tune_args = subtree->access<device_addr_t>("tune_args").get();          is_int_n = boost::iequals(tune_args.get("mode_n",""), "integer"); +        double target_pfd_freq = _rx_target_pfd_freq; +        if (is_int_n and tune_args.has_key("int_n_step")) +        { +            target_pfd_freq = tune_args.cast<double>("int_n_step", _rx_target_pfd_freq); +            if (target_pfd_freq > _rx_target_pfd_freq) +            { +                UHD_MSG(warning) +                    << boost::format("Requested int_n_step of %f Mhz too large, clipping to %f MHz") +                    % (target_pfd_freq/1e6) +                    % (_rx_target_pfd_freq/1e6) +                    << std::endl; +                target_pfd_freq = _rx_target_pfd_freq; +            } +        }          // Clip the frequency to the valid range          freq = ubx_freq_range.clip(freq); @@ -848,10 +877,10 @@ private:              set_cpld_field(RXLB_SEL, 1);              set_cpld_field(RXHB_SEL, 0);              // Set LO1 to IF of 2380 MHz (2440 MHz filter center minus 60 MHz offset to minimize LO leakage) -            freq_lo1 = _rxlo1->set_frequency(2380*fMHz, ref_freq, _rx_target_pfd_freq, is_int_n); +            freq_lo1 = _rxlo1->set_frequency(2380*fMHz, ref_freq, target_pfd_freq, is_int_n);              _rxlo1->set_output_power(max287x_iface::OUTPUT_POWER_5DBM);              // Set LO2 to IF minus desired frequency -            freq_lo2 = _rxlo2->set_frequency(freq_lo1 - freq, ref_freq, _rx_target_pfd_freq, is_int_n); +            freq_lo2 = _rxlo2->set_frequency(freq_lo1 - freq, ref_freq, target_pfd_freq, is_int_n);              _rxlo2->set_output_power(max287x_iface::OUTPUT_POWER_2DBM);          }          else if ((freq >= 100*fMHz) && (freq < 500*fMHz)) @@ -864,10 +893,10 @@ private:              set_cpld_field(RXLB_SEL, 1);              set_cpld_field(RXHB_SEL, 0);              // Set LO1 to IF of 2440 (center of filter) -            freq_lo1 = _rxlo1->set_frequency(2440*fMHz, ref_freq, _rx_target_pfd_freq, is_int_n); +            freq_lo1 = _rxlo1->set_frequency(2440*fMHz, ref_freq, target_pfd_freq, is_int_n);              _rxlo1->set_output_power(max287x_iface::OUTPUT_POWER_5DBM);              // Set LO2 to IF minus desired frequency -            freq_lo2 = _rxlo2->set_frequency(freq_lo1 - freq, ref_freq, _rx_target_pfd_freq, is_int_n); +            freq_lo2 = _rxlo2->set_frequency(freq_lo1 - freq, ref_freq, target_pfd_freq, is_int_n);              _rxlo1->set_output_power(max287x_iface::OUTPUT_POWER_2DBM);          }          else if ((freq >= 500*fMHz) && (freq < 800*fMHz)) @@ -879,7 +908,7 @@ private:              set_cpld_field(RXLO1_FSEL1, 1);              set_cpld_field(RXLB_SEL, 0);              set_cpld_field(RXHB_SEL, 1); -            freq_lo1 = _rxlo1->set_frequency(freq, ref_freq, _rx_target_pfd_freq, is_int_n); +            freq_lo1 = _rxlo1->set_frequency(freq, ref_freq, target_pfd_freq, is_int_n);              _rxlo1->set_output_power(max287x_iface::OUTPUT_POWER_2DBM);          }          else if ((freq >= 800*fMHz) && (freq < 1000*fMHz)) @@ -891,7 +920,7 @@ private:              set_cpld_field(RXLO1_FSEL1, 1);              set_cpld_field(RXLB_SEL, 0);              set_cpld_field(RXHB_SEL, 1); -            freq_lo1 = _rxlo1->set_frequency(freq, ref_freq, _rx_target_pfd_freq, is_int_n); +            freq_lo1 = _rxlo1->set_frequency(freq, ref_freq, target_pfd_freq, is_int_n);              _rxlo1->set_output_power(max287x_iface::OUTPUT_POWER_5DBM);          }          else if ((freq >= 1000*fMHz) && (freq < 1500*fMHz)) @@ -903,7 +932,7 @@ private:              set_cpld_field(RXLO1_FSEL1, 0);              set_cpld_field(RXLB_SEL, 0);              set_cpld_field(RXHB_SEL, 1); -            freq_lo1 = _rxlo1->set_frequency(freq, ref_freq, _rx_target_pfd_freq, is_int_n); +            freq_lo1 = _rxlo1->set_frequency(freq, ref_freq, target_pfd_freq, is_int_n);              _rxlo1->set_output_power(max287x_iface::OUTPUT_POWER_2DBM);          }          else if ((freq >= 1500*fMHz) && (freq < 2200*fMHz)) @@ -915,7 +944,7 @@ private:              set_cpld_field(RXLO1_FSEL1, 0);              set_cpld_field(RXLB_SEL, 0);              set_cpld_field(RXHB_SEL, 1); -            freq_lo1 = _rxlo1->set_frequency(freq, ref_freq, _rx_target_pfd_freq, is_int_n); +            freq_lo1 = _rxlo1->set_frequency(freq, ref_freq, target_pfd_freq, is_int_n);              _rxlo1->set_output_power(max287x_iface::OUTPUT_POWER_2DBM);          }          else if ((freq >= 2200*fMHz) && (freq < 2500*fMHz)) @@ -927,7 +956,7 @@ private:              set_cpld_field(RXLO1_FSEL1, 0);              set_cpld_field(RXLB_SEL, 0);              set_cpld_field(RXHB_SEL, 1); -            freq_lo1 = _rxlo1->set_frequency(freq, ref_freq, _rx_target_pfd_freq, is_int_n); +            freq_lo1 = _rxlo1->set_frequency(freq, ref_freq, target_pfd_freq, is_int_n);              _rxlo1->set_output_power(max287x_iface::OUTPUT_POWER_2DBM);          }          else if ((freq >= 2500*fMHz) && (freq <= 6000*fMHz)) @@ -939,7 +968,7 @@ private:              set_cpld_field(RXLO1_FSEL1, 0);              set_cpld_field(RXLB_SEL, 0);              set_cpld_field(RXHB_SEL, 1); -            freq_lo1 = _rxlo1->set_frequency(freq, ref_freq, _rx_target_pfd_freq, is_int_n); +            freq_lo1 = _rxlo1->set_frequency(freq, ref_freq, target_pfd_freq, is_int_n);              _rxlo1->set_output_power(max287x_iface::OUTPUT_POWER_5DBM);          } diff --git a/host/lib/usrp/dboard/db_wbx_simple.cpp b/host/lib/usrp/dboard/db_wbx_simple.cpp index c8f2be155..dda2def95 100644 --- a/host/lib/usrp/dboard/db_wbx_simple.cpp +++ b/host/lib/usrp/dboard/db_wbx_simple.cpp @@ -112,14 +112,14 @@ wbx_simple::wbx_simple(ctor_args_t args) : wbx_base(args){      this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, ANTSW_IO, ANTSW_IO);      //setup ATR for the antenna switches (constant) -    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_IDLE,        ANT_RX, ANTSW_IO); -    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_RX_ONLY,     ANT_RX, ANTSW_IO); -    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_TX_ONLY,     ANT_TX, ANTSW_IO); -    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_FULL_DUPLEX, ANT_TX, ANTSW_IO); - -    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE,        ANT_TXRX, ANTSW_IO); -    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY,     ANT_RX2, ANTSW_IO); -    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, ANT_RX2, ANTSW_IO); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_IDLE,        ANT_RX, ANTSW_IO); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_RX_ONLY,     ANT_RX, ANTSW_IO); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_TX_ONLY,     ANT_TX, ANTSW_IO); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_FULL_DUPLEX, ANT_TX, ANTSW_IO); + +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_IDLE,        ANT_TXRX, ANTSW_IO); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_TX_ONLY,     ANT_RX2, ANTSW_IO); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_FULL_DUPLEX, ANT_RX2, ANTSW_IO);  }  wbx_simple::~wbx_simple(void){ @@ -138,14 +138,14 @@ void wbx_simple::set_rx_ant(const std::string &ant){      //write the new antenna setting to atr regs      if (_rx_ant == "CAL") { -        this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY,     ANT_TXRX, ANTSW_IO); -        this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, ANT_TXRX, ANTSW_IO); -        this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY,     ANT_TXRX, ANTSW_IO); +        this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_TX_ONLY,     ANT_TXRX, ANTSW_IO); +        this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_FULL_DUPLEX, ANT_TXRX, ANTSW_IO); +        this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_RX_ONLY,     ANT_TXRX, ANTSW_IO);      }       else { -        this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY,     ANT_RX2, ANTSW_IO); -        this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, ANT_RX2, ANTSW_IO); -        this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY, ((_rx_ant == "TX/RX")? ANT_TXRX : ANT_RX2), ANTSW_IO); +        this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_TX_ONLY,     ANT_RX2, ANTSW_IO); +        this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_FULL_DUPLEX, ANT_RX2, ANTSW_IO); +        this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_RX_ONLY, ((_rx_ant == "TX/RX")? ANT_TXRX : ANT_RX2), ANTSW_IO);      }  } @@ -154,11 +154,11 @@ void wbx_simple::set_tx_ant(const std::string &ant){      //write the new antenna setting to atr regs      if (ant == "CAL") { -        this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_TX_ONLY,     ANT_RX, ANTSW_IO); -        this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_FULL_DUPLEX, ANT_RX, ANTSW_IO); +        this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_TX_ONLY,     ANT_RX, ANTSW_IO); +        this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_FULL_DUPLEX, ANT_RX, ANTSW_IO);      }       else { -        this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_TX_ONLY,     ANT_TX, ANTSW_IO); -        this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_FULL_DUPLEX, ANT_TX, ANTSW_IO); +        this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_TX_ONLY,     ANT_TX, ANTSW_IO); +        this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_FULL_DUPLEX, ANT_TX, ANTSW_IO);      }  } diff --git a/host/lib/usrp/dboard/db_wbx_version2.cpp b/host/lib/usrp/dboard/db_wbx_version2.cpp index 93047fb7a..78b5b2871 100644 --- a/host/lib/usrp/dboard/db_wbx_version2.cpp +++ b/host/lib/usrp/dboard/db_wbx_version2.cpp @@ -117,15 +117,15 @@ wbx_base::wbx_version2::wbx_version2(wbx_base *_self_wbx_base) {      self_base->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, RX_PUP_5V|RX_PUP_3V|ADF435X_CE|RXBB_PDB|ADF435X_PDBRF|RX_ATTN_MASK);      //setup ATR for the mixer enables (always enabled to prevent phase slip between bursts) -    self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_IDLE,        v2_tx_mod, TX_MIXER_DIS | v2_tx_mod); -    self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_RX_ONLY,     v2_tx_mod, TX_MIXER_DIS | v2_tx_mod); -    self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_TX_ONLY,     v2_tx_mod, TX_MIXER_DIS | v2_tx_mod); -    self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_FULL_DUPLEX, v2_tx_mod, TX_MIXER_DIS | v2_tx_mod); - -    self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE,        RX_MIXER_ENB, RX_MIXER_DIS | RX_MIXER_ENB); -    self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY,     RX_MIXER_ENB, RX_MIXER_DIS | RX_MIXER_ENB); -    self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY,     RX_MIXER_ENB, RX_MIXER_DIS | RX_MIXER_ENB); -    self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, RX_MIXER_ENB, RX_MIXER_DIS | RX_MIXER_ENB); +    self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_IDLE,        v2_tx_mod, TX_MIXER_DIS | v2_tx_mod); +    self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_RX_ONLY,     v2_tx_mod, TX_MIXER_DIS | v2_tx_mod); +    self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_TX_ONLY,     v2_tx_mod, TX_MIXER_DIS | v2_tx_mod); +    self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_FULL_DUPLEX, v2_tx_mod, TX_MIXER_DIS | v2_tx_mod); + +    self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_IDLE,        RX_MIXER_ENB, RX_MIXER_DIS | RX_MIXER_ENB); +    self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_TX_ONLY,     RX_MIXER_ENB, RX_MIXER_DIS | RX_MIXER_ENB); +    self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_RX_ONLY,     RX_MIXER_ENB, RX_MIXER_DIS | RX_MIXER_ENB); +    self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_FULL_DUPLEX, RX_MIXER_ENB, RX_MIXER_DIS | RX_MIXER_ENB);  }  wbx_base::wbx_version2::~wbx_version2(void){ diff --git a/host/lib/usrp/dboard/db_wbx_version3.cpp b/host/lib/usrp/dboard/db_wbx_version3.cpp index 6927ae4e4..a5821ffc2 100644 --- a/host/lib/usrp/dboard/db_wbx_version3.cpp +++ b/host/lib/usrp/dboard/db_wbx_version3.cpp @@ -129,29 +129,29 @@ wbx_base::wbx_version3::wbx_version3(wbx_base *_self_wbx_base) {      //slip between bursts).  set TX gain iobits to min gain (max attenuation)      //when RX_ONLY or IDLE to suppress LO leakage      self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, \ -            dboard_iface::ATR_REG_IDLE, v3_tx_mod, \ +            gpio_atr::ATR_REG_IDLE, v3_tx_mod, \              TX_ATTN_MASK | TX_MIXER_DIS | v3_tx_mod);      self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, \ -            dboard_iface::ATR_REG_RX_ONLY, v3_tx_mod, \ +            gpio_atr::ATR_REG_RX_ONLY, v3_tx_mod, \              TX_ATTN_MASK | TX_MIXER_DIS | v3_tx_mod);      self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, \ -            dboard_iface::ATR_REG_TX_ONLY, v3_tx_mod, \ +            gpio_atr::ATR_REG_TX_ONLY, v3_tx_mod, \              TX_ATTN_MASK | TX_MIXER_DIS | v3_tx_mod);      self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, \ -            dboard_iface::ATR_REG_FULL_DUPLEX, v3_tx_mod, \ +            gpio_atr::ATR_REG_FULL_DUPLEX, v3_tx_mod, \              TX_ATTN_MASK | TX_MIXER_DIS | v3_tx_mod);      self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, \ -            dboard_iface::ATR_REG_IDLE, \ +            gpio_atr::ATR_REG_IDLE, \              RX_MIXER_ENB, RX_MIXER_DIS | RX_MIXER_ENB);      self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, \ -            dboard_iface::ATR_REG_TX_ONLY, \ +            gpio_atr::ATR_REG_TX_ONLY, \              RX_MIXER_ENB, RX_MIXER_DIS | RX_MIXER_ENB);      self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, \ -            dboard_iface::ATR_REG_RX_ONLY, \ +            gpio_atr::ATR_REG_RX_ONLY, \              RX_MIXER_ENB, RX_MIXER_DIS | RX_MIXER_ENB);      self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, \ -            dboard_iface::ATR_REG_FULL_DUPLEX, \ +            gpio_atr::ATR_REG_FULL_DUPLEX, \              RX_MIXER_ENB, RX_MIXER_DIS | RX_MIXER_ENB);  } @@ -181,8 +181,8 @@ double wbx_base::wbx_version3::set_tx_gain(double gain, const std::string &name)          //write the new gain to tx gpio outputs          //Update ATR with gain io_bits, only update for TX_ONLY and FULL_DUPLEX ATR states -        self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_TX_ONLY,     io_bits, TX_ATTN_MASK); -        self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_FULL_DUPLEX, io_bits, TX_ATTN_MASK); +        self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_TX_ONLY,     io_bits, TX_ATTN_MASK); +        self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_FULL_DUPLEX, io_bits, TX_ATTN_MASK);      }      else UHD_THROW_INVALID_CODE_PATH();      return self_base->_tx_gains[name]; //shadow diff --git a/host/lib/usrp/dboard/db_wbx_version4.cpp b/host/lib/usrp/dboard/db_wbx_version4.cpp index 81cdaefac..327ae675b 100644 --- a/host/lib/usrp/dboard/db_wbx_version4.cpp +++ b/host/lib/usrp/dboard/db_wbx_version4.cpp @@ -136,29 +136,29 @@ wbx_base::wbx_version4::wbx_version4(wbx_base *_self_wbx_base) {      //between bursts) set TX gain iobits to min gain (max attenuation) when      //RX_ONLY or IDLE to suppress LO leakage      self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, \ -            dboard_iface::ATR_REG_IDLE, v4_tx_mod, \ +            gpio_atr::ATR_REG_IDLE, v4_tx_mod, \              TX_ATTN_MASK | TX_MIXER_DIS | v4_tx_mod);      self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, \ -            dboard_iface::ATR_REG_RX_ONLY, v4_tx_mod, \ +            gpio_atr::ATR_REG_RX_ONLY, v4_tx_mod, \              TX_ATTN_MASK | TX_MIXER_DIS | v4_tx_mod);      self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, \ -            dboard_iface::ATR_REG_TX_ONLY, v4_tx_mod, \ +            gpio_atr::ATR_REG_TX_ONLY, v4_tx_mod, \              TX_ATTN_MASK | TX_MIXER_DIS | v4_tx_mod);      self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, \ -            dboard_iface::ATR_REG_FULL_DUPLEX, v4_tx_mod, \ +            gpio_atr::ATR_REG_FULL_DUPLEX, v4_tx_mod, \              TX_ATTN_MASK | TX_MIXER_DIS | v4_tx_mod);      self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, \ -            dboard_iface::ATR_REG_IDLE, \ +            gpio_atr::ATR_REG_IDLE, \              RX_MIXER_ENB, RX_MIXER_DIS | RX_MIXER_ENB);      self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, \ -            dboard_iface::ATR_REG_TX_ONLY, \ +            gpio_atr::ATR_REG_TX_ONLY, \              RX_MIXER_ENB, RX_MIXER_DIS | RX_MIXER_ENB);      self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, \ -            dboard_iface::ATR_REG_RX_ONLY, \ +            gpio_atr::ATR_REG_RX_ONLY, \              RX_MIXER_ENB, RX_MIXER_DIS | RX_MIXER_ENB);      self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, \ -            dboard_iface::ATR_REG_FULL_DUPLEX, \ +            gpio_atr::ATR_REG_FULL_DUPLEX, \              RX_MIXER_ENB, RX_MIXER_DIS | RX_MIXER_ENB);  } @@ -188,8 +188,8 @@ double wbx_base::wbx_version4::set_tx_gain(double gain, const std::string &name)          //write the new gain to tx gpio outputs          //Update ATR with gain io_bits, only update for TX_ONLY and FULL_DUPLEX ATR states -        self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_TX_ONLY,     io_bits, TX_ATTN_MASK); -        self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_FULL_DUPLEX, io_bits, TX_ATTN_MASK); +        self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_TX_ONLY,     io_bits, TX_ATTN_MASK); +        self_base->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_FULL_DUPLEX, io_bits, TX_ATTN_MASK);      }      else UHD_THROW_INVALID_CODE_PATH(); diff --git a/host/lib/usrp/dboard/db_xcvr2450.cpp b/host/lib/usrp/dboard/db_xcvr2450.cpp index 50c67991a..092f84548 100644 --- a/host/lib/usrp/dboard/db_xcvr2450.cpp +++ b/host/lib/usrp/dboard/db_xcvr2450.cpp @@ -315,12 +315,12 @@ xcvr2450::~xcvr2450(void){  void xcvr2450::spi_reset(void){      //spi reset mode: global enable = off, tx and rx enable = on -    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_IDLE, TX_ENB_TXIO); -    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, RX_ENB_RXIO | POWER_DOWN_RXIO); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_IDLE, TX_ENB_TXIO); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_IDLE, RX_ENB_RXIO | POWER_DOWN_RXIO);      boost::this_thread::sleep(boost::posix_time::milliseconds(10));      //take it back out of spi reset mode and wait a bit -    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, RX_DIS_RXIO | POWER_UP_RXIO); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_IDLE, RX_DIS_RXIO | POWER_UP_RXIO);      boost::this_thread::sleep(boost::posix_time::milliseconds(10));  } @@ -337,16 +337,16 @@ void xcvr2450::update_atr(void){      int ad9515div  = (_ad9515div == 3)? AD9515DIV_3_TXIO : AD9515DIV_2_TXIO;      //set the tx registers -    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_IDLE,        band_sel | ad9515div | TX_DIS_TXIO); -    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_RX_ONLY,     band_sel | ad9515div | TX_DIS_TXIO | rx_ant_sel); -    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_TX_ONLY,     band_sel | ad9515div | TX_ENB_TXIO | tx_ant_sel); -    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, dboard_iface::ATR_REG_FULL_DUPLEX, band_sel | ad9515div | TX_ENB_TXIO | xx_ant_sel); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_IDLE,        band_sel | ad9515div | TX_DIS_TXIO); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_RX_ONLY,     band_sel | ad9515div | TX_DIS_TXIO | rx_ant_sel); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_TX_ONLY,     band_sel | ad9515div | TX_ENB_TXIO | tx_ant_sel); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_TX, gpio_atr::ATR_REG_FULL_DUPLEX, band_sel | ad9515div | TX_ENB_TXIO | xx_ant_sel);      //set the rx registers -    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE,        POWER_UP_RXIO | RX_DIS_RXIO); -    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY,     POWER_UP_RXIO | RX_ENB_RXIO); -    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY,     POWER_UP_RXIO | RX_DIS_RXIO); -    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, POWER_UP_RXIO | RX_DIS_RXIO); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_IDLE,        POWER_UP_RXIO | RX_DIS_RXIO); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_RX_ONLY,     POWER_UP_RXIO | RX_ENB_RXIO); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_TX_ONLY,     POWER_UP_RXIO | RX_DIS_RXIO); +    this->get_iface()->set_atr_reg(dboard_iface::UNIT_RX, gpio_atr::ATR_REG_FULL_DUPLEX, POWER_UP_RXIO | RX_DIS_RXIO);  }  /*********************************************************************** diff --git a/host/lib/usrp/e100/CMakeLists.txt b/host/lib/usrp/e100/CMakeLists.txt index 2a1e14eab..da77b85dc 100644 --- a/host/lib/usrp/e100/CMakeLists.txt +++ b/host/lib/usrp/e100/CMakeLists.txt @@ -22,8 +22,6 @@  ########################################################################  # Conditionally configure the USRP-E100 support  ######################################################################## -LIBUHD_REGISTER_COMPONENT("E100" ENABLE_E100 OFF "ENABLE_LIBUHD;LINUX" OFF OFF) -  IF(ENABLE_E100)      INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include) diff --git a/host/lib/usrp/e300/CMakeLists.txt b/host/lib/usrp/e300/CMakeLists.txt index 9c8aa29b9..68c3520e4 100644 --- a/host/lib/usrp/e300/CMakeLists.txt +++ b/host/lib/usrp/e300/CMakeLists.txt @@ -24,8 +24,6 @@  ########################################################################  find_package(UDev) -LIBUHD_REGISTER_COMPONENT("E300" ENABLE_E300 OFF "ENABLE_LIBUHD" OFF OFF) -  IF(ENABLE_E300)      LIST(APPEND E300_SOURCES          ${CMAKE_CURRENT_SOURCE_DIR}/e300_impl.cpp diff --git a/host/lib/usrp/e300/e300_fpga_defs.hpp b/host/lib/usrp/e300/e300_fpga_defs.hpp index a8fa60d9d..dcfb05021 100644 --- a/host/lib/usrp/e300/e300_fpga_defs.hpp +++ b/host/lib/usrp/e300/e300_fpga_defs.hpp @@ -21,7 +21,7 @@ namespace uhd { namespace usrp { namespace e300 { namespace fpga {  static const size_t NUM_RADIOS = 2; -static const boost::uint32_t COMPAT_MAJOR = 11; +static const boost::uint32_t COMPAT_MAJOR = 13;  static const boost::uint32_t COMPAT_MINOR = 0;  }}}} // namespace diff --git a/host/lib/usrp/e300/e300_impl.cpp b/host/lib/usrp/e300/e300_impl.cpp index 6d66e83c0..c82ab3d0e 100644 --- a/host/lib/usrp/e300/e300_impl.cpp +++ b/host/lib/usrp/e300/e300_impl.cpp @@ -48,6 +48,7 @@  using namespace uhd;  using namespace uhd::usrp; +using namespace uhd::usrp::gpio_atr;  using namespace uhd::transport;  namespace fs = boost::filesystem;  namespace asio = boost::asio; @@ -512,15 +513,15 @@ e300_impl::e300_impl(const uhd::device_addr_t &device_addr)      ////////////////////////////////////////////////////////////////////      // internal gpios      //////////////////////////////////////////////////////////////////// -    gpio_core_200::sptr fp_gpio = gpio_core_200::make(_radio_perifs[0].ctrl, radio::sr_addr(radio::FP_GPIO), radio::RB32_FP_GPIO); +    gpio_atr_3000::sptr fp_gpio = gpio_atr_3000::make(_radio_perifs[0].ctrl, radio::sr_addr(radio::FP_GPIO), radio::RB32_FP_GPIO);      BOOST_FOREACH(const gpio_attr_map_t::value_type attr, gpio_attr_map)      {          _tree->create<boost::uint32_t>(mb_path / "gpio" / "INT0" / attr.second) -            .subscribe(boost::bind(&e300_impl::_set_internal_gpio, this, fp_gpio, attr.first, _1)) +            .subscribe(boost::bind(&gpio_atr_3000::set_gpio_attr, fp_gpio, attr.first, _1))              .set(0);      }      _tree->create<boost::uint8_t>(mb_path / "gpio" / "INT0" / "READBACK") -        .publish(boost::bind(&e300_impl::_get_internal_gpio, this, fp_gpio)); +        .publish(boost::bind(&gpio_atr_3000::read_gpio, fp_gpio));      //////////////////////////////////////////////////////////////////// @@ -623,37 +624,6 @@ e300_impl::e300_impl(const uhd::device_addr_t &device_addr)      _tree->access<subdev_spec_t>(mb_path / "tx_subdev_spec").set(tx_spec);  } -boost::uint8_t e300_impl::_get_internal_gpio(gpio_core_200::sptr gpio) -{ -    return boost::uint32_t(gpio->read_gpio(dboard_iface::UNIT_RX)); -} - -void e300_impl::_set_internal_gpio( -    gpio_core_200::sptr gpio, -    const gpio_attr_t attr, -    const boost::uint32_t value) -{ -    switch (attr) -    { -    case GPIO_CTRL: -        return gpio->set_pin_ctrl(dboard_iface::UNIT_RX, value); -    case GPIO_DDR: -        return gpio->set_gpio_ddr(dboard_iface::UNIT_RX, value); -    case GPIO_OUT: -        return gpio->set_gpio_out(dboard_iface::UNIT_RX, value); -    case GPIO_ATR_0X: -        return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, value); -    case GPIO_ATR_RX: -        return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY, value); -    case GPIO_ATR_TX: -        return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY, value); -    case GPIO_ATR_XX: -        return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, value); -    default: -        UHD_THROW_INVALID_CODE_PATH(); -    } -} -  uhd::sensor_value_t e300_impl::_get_fe_pll_lock(const bool is_tx)  {      const boost::uint32_t st = @@ -978,7 +948,8 @@ void e300_impl::_setup_radio(const size_t dspno)      ////////////////////////////////////////////////////////////////////      // Set up peripherals      //////////////////////////////////////////////////////////////////// -    perif.atr = gpio_core_200_32wo::make(perif.ctrl, radio::sr_addr(radio::GPIO)); +    perif.atr = gpio_atr_3000::make_write_only(perif.ctrl, radio::sr_addr(radio::GPIO)); +    perif.atr->set_atr_mode(MODE_ATR, 0xFFFFFFFF);      perif.rx_fe = rx_frontend_core_200::make(perif.ctrl, radio::sr_addr(radio::RX_FRONT));      perif.rx_fe->set_dc_offset(rx_frontend_core_200::DEFAULT_DC_OFFSET_VALUE);      perif.rx_fe->set_dc_offset_auto(rx_frontend_core_200::DEFAULT_DC_OFFSET_ENABLE); @@ -1027,7 +998,6 @@ void e300_impl::_setup_radio(const size_t dspno)      // create tx dsp control objects      ////////////////////////////////////////////////////////////////////      _tree->access<double>(mb_path / "tick_rate") -        .subscribe(boost::bind(&tx_vita_core_3000::set_tick_rate, perif.deframer, _1))          .subscribe(boost::bind(&tx_dsp_core_3000::set_tick_rate, perif.duc, _1));      const fs_path tx_dsp_path = mb_path / "tx_dsps" / str(boost::format("%u") % dspno);      perif.duc->populate_subtree(_tree->subtree(tx_dsp_path)); @@ -1291,11 +1261,11 @@ void e300_impl::_update_atrs(void)          if (enb_tx)              fd_reg |= tx_enables | xx_leds; -        gpio_core_200_32wo::sptr atr = _radio_perifs[instance].atr; -        atr->set_atr_reg(dboard_iface::ATR_REG_IDLE, oo_reg); -        atr->set_atr_reg(dboard_iface::ATR_REG_RX_ONLY, rx_reg); -        atr->set_atr_reg(dboard_iface::ATR_REG_TX_ONLY, tx_reg); -        atr->set_atr_reg(dboard_iface::ATR_REG_FULL_DUPLEX, fd_reg); +        gpio_atr_3000::sptr atr = _radio_perifs[instance].atr; +        atr->set_atr_reg(ATR_REG_IDLE, oo_reg); +        atr->set_atr_reg(ATR_REG_RX_ONLY, rx_reg); +        atr->set_atr_reg(ATR_REG_TX_ONLY, tx_reg); +        atr->set_atr_reg(ATR_REG_FULL_DUPLEX, fd_reg);      }  } diff --git a/host/lib/usrp/e300/e300_impl.hpp b/host/lib/usrp/e300/e300_impl.hpp index 8aff51466..9b39c7468 100644 --- a/host/lib/usrp/e300/e300_impl.hpp +++ b/host/lib/usrp/e300/e300_impl.hpp @@ -41,7 +41,7 @@  #include "tx_dsp_core_3000.hpp"  #include "ad9361_ctrl.hpp"  #include "ad936x_manager.hpp" -#include "gpio_core_200.hpp" +#include "gpio_atr_3000.hpp"  #include "e300_global_regs.hpp"  #include "e300_i2c.hpp" @@ -146,7 +146,7 @@ private: // types      struct radio_perifs_t      {          radio_ctrl_core_3000::sptr ctrl; -        gpio_core_200_32wo::sptr atr; +        gpio_atr::gpio_atr_3000::sptr atr;          time_core_3000::sptr time64;          rx_vita_core_3000::sptr framer;          rx_dsp_core_3000::sptr ddc; @@ -277,14 +277,6 @@ private: // methods      // get frontend lock sensor      uhd::sensor_value_t _get_fe_pll_lock(const bool is_tx); -    // internal gpios -    boost::uint8_t _get_internal_gpio(gpio_core_200::sptr); - -    void _set_internal_gpio( -        gpio_core_200::sptr gpio, -        const gpio_attr_t attr, -        const boost::uint32_t value); -  private: // members      uhd::device_addr_t                     _device_addr;      xport_t                                _xport_path; diff --git a/host/lib/usrp/e300/e300_io_impl.cpp b/host/lib/usrp/e300/e300_io_impl.cpp index 29d250c8f..209a73077 100644 --- a/host/lib/usrp/e300/e300_io_impl.cpp +++ b/host/lib/usrp/e300/e300_io_impl.cpp @@ -87,7 +87,6 @@ void e300_impl::_update_tick_rate(const double rate)              boost::dynamic_pointer_cast<sph::send_packet_streamer>(perif.tx_streamer.lock());          if (my_streamer)              my_streamer->set_tick_rate(rate); -        perif.deframer->set_tick_rate(_tick_rate);      }  } diff --git a/host/lib/usrp/e300/e300_regs.hpp b/host/lib/usrp/e300/e300_regs.hpp index 846c759a4..74e45df00 100644 --- a/host/lib/usrp/e300/e300_regs.hpp +++ b/host/lib/usrp/e300/e300_regs.hpp @@ -41,7 +41,7 @@ static const uint32_t TIME       = 128;  static const uint32_t RX_DSP     = 144;  static const uint32_t TX_DSP     = 184;  static const uint32_t LEDS       = 195; -static const uint32_t FP_GPIO    = 200; +static const uint32_t FP_GPIO    = 201;  static const uint32_t RX_FRONT   = 208;  static const uint32_t TX_FRONT   = 216;  static const uint32_t CODEC_IDLE = 250; diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp index 396237e24..dbc0ebed2 100644 --- a/host/lib/usrp/multi_usrp.cpp +++ b/host/lib/usrp/multi_usrp.cpp @@ -438,8 +438,10 @@ public:       ******************************************************************/      void set_master_clock_rate(double rate, size_t mboard){          if (mboard != ALL_MBOARDS){ -            if (_tree->exists(mb_root(mboard) / "auto_tick_rate")) { +            if (_tree->exists(mb_root(mboard) / "auto_tick_rate") +                    and _tree->access<bool>(mb_root(mboard) / "auto_tick_rate").get()) {                  _tree->access<bool>(mb_root(mboard) / "auto_tick_rate").set(false); +                UHD_MSG(status) << "Setting master clock rate selection to 'manual'." << std::endl;              }              _tree->access<double>(mb_root(mboard) / "tick_rate").set(rate);              return; @@ -1346,10 +1348,10 @@ public:              if (attr == "CTRL") iface->set_pin_ctrl(unit, boost::uint16_t(value), boost::uint16_t(mask));              if (attr == "DDR") iface->set_gpio_ddr(unit, boost::uint16_t(value), boost::uint16_t(mask));              if (attr == "OUT") iface->set_gpio_out(unit, boost::uint16_t(value), boost::uint16_t(mask)); -            if (attr == "ATR_0X") iface->set_atr_reg(unit, dboard_iface::ATR_REG_IDLE, boost::uint16_t(value), boost::uint16_t(mask)); -            if (attr == "ATR_RX") iface->set_atr_reg(unit, dboard_iface::ATR_REG_RX_ONLY, boost::uint16_t(value), boost::uint16_t(mask)); -            if (attr == "ATR_TX") iface->set_atr_reg(unit, dboard_iface::ATR_REG_TX_ONLY, boost::uint16_t(value), boost::uint16_t(mask)); -            if (attr == "ATR_XX") iface->set_atr_reg(unit, dboard_iface::ATR_REG_FULL_DUPLEX, boost::uint16_t(value), boost::uint16_t(mask)); +            if (attr == "ATR_0X") iface->set_atr_reg(unit, gpio_atr::ATR_REG_IDLE, boost::uint16_t(value), boost::uint16_t(mask)); +            if (attr == "ATR_RX") iface->set_atr_reg(unit, gpio_atr::ATR_REG_RX_ONLY, boost::uint16_t(value), boost::uint16_t(mask)); +            if (attr == "ATR_TX") iface->set_atr_reg(unit, gpio_atr::ATR_REG_TX_ONLY, boost::uint16_t(value), boost::uint16_t(mask)); +            if (attr == "ATR_XX") iface->set_atr_reg(unit, gpio_atr::ATR_REG_FULL_DUPLEX, boost::uint16_t(value), boost::uint16_t(mask));          }      } @@ -1367,10 +1369,10 @@ public:              if (attr == "CTRL") return iface->get_pin_ctrl(unit);              if (attr == "DDR") return iface->get_gpio_ddr(unit);              if (attr == "OUT") return iface->get_gpio_out(unit); -            if (attr == "ATR_0X") return iface->get_atr_reg(unit, dboard_iface::ATR_REG_IDLE); -            if (attr == "ATR_RX") return iface->get_atr_reg(unit, dboard_iface::ATR_REG_RX_ONLY); -            if (attr == "ATR_TX") return iface->get_atr_reg(unit, dboard_iface::ATR_REG_TX_ONLY); -            if (attr == "ATR_XX") return iface->get_atr_reg(unit, dboard_iface::ATR_REG_FULL_DUPLEX); +            if (attr == "ATR_0X") return iface->get_atr_reg(unit, gpio_atr::ATR_REG_IDLE); +            if (attr == "ATR_RX") return iface->get_atr_reg(unit, gpio_atr::ATR_REG_RX_ONLY); +            if (attr == "ATR_TX") return iface->get_atr_reg(unit, gpio_atr::ATR_REG_TX_ONLY); +            if (attr == "ATR_XX") return iface->get_atr_reg(unit, gpio_atr::ATR_REG_FULL_DUPLEX);              if (attr == "READBACK") return iface->read_gpio(unit);          }          return 0; diff --git a/host/lib/usrp/usrp1/CMakeLists.txt b/host/lib/usrp/usrp1/CMakeLists.txt index 47344e841..6924ba3b0 100644 --- a/host/lib/usrp/usrp1/CMakeLists.txt +++ b/host/lib/usrp/usrp1/CMakeLists.txt @@ -22,8 +22,6 @@  ########################################################################  # Conditionally configure the USRP1 support  ######################################################################## -LIBUHD_REGISTER_COMPONENT("USRP1" ENABLE_USRP1 ON "ENABLE_LIBUHD;ENABLE_USB" OFF OFF) -  IF(ENABLE_USRP1)      LIBUHD_APPEND_SOURCES(          ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.cpp diff --git a/host/lib/usrp/usrp1/dboard_iface.cpp b/host/lib/usrp/usrp1/dboard_iface.cpp index 4c3141d9e..502d0fbe3 100644 --- a/host/lib/usrp/usrp1/dboard_iface.cpp +++ b/host/lib/usrp/usrp1/dboard_iface.cpp @@ -63,6 +63,7 @@  using namespace uhd;  using namespace uhd::usrp; +using namespace uhd::usrp::gpio_atr;  using namespace boost::assign;  static const dboard_id_t tvrx_id(0x0040); diff --git a/host/lib/usrp/usrp2/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt index d9894adaf..edf77a654 100644 --- a/host/lib/usrp/usrp2/CMakeLists.txt +++ b/host/lib/usrp/usrp2/CMakeLists.txt @@ -22,8 +22,6 @@  ########################################################################  # Conditionally configure the USRP2 support  ######################################################################## -LIBUHD_REGISTER_COMPONENT("USRP2" ENABLE_USRP2 ON "ENABLE_LIBUHD" OFF OFF) -  IF(ENABLE_USRP2)      LIBUHD_APPEND_SOURCES(          ${CMAKE_CURRENT_SOURCE_DIR}/clock_ctrl.cpp diff --git a/host/lib/usrp/x300/CMakeLists.txt b/host/lib/usrp/x300/CMakeLists.txt index 3d6348eec..f8b129f89 100644 --- a/host/lib/usrp/x300/CMakeLists.txt +++ b/host/lib/usrp/x300/CMakeLists.txt @@ -22,8 +22,6 @@  ########################################################################  # Conditionally configure the X300 support  ######################################################################## -LIBUHD_REGISTER_COMPONENT("X300" ENABLE_X300 ON "ENABLE_LIBUHD" OFF OFF) -  IF(ENABLE_X300)      LIBUHD_APPEND_SOURCES(          ${CMAKE_CURRENT_SOURCE_DIR}/x300_impl.cpp diff --git a/host/lib/usrp/x300/x300_fw_common.h b/host/lib/usrp/x300/x300_fw_common.h index 1b88db69a..4c5051eaa 100644 --- a/host/lib/usrp/x300/x300_fw_common.h +++ b/host/lib/usrp/x300/x300_fw_common.h @@ -33,7 +33,7 @@ extern "C" {  #define X300_REVISION_MIN    2  #define X300_FW_COMPAT_MAJOR 4  #define X300_FW_COMPAT_MINOR 0 -#define X300_FPGA_COMPAT_MAJOR 15 +#define X300_FPGA_COMPAT_MAJOR 18  //shared memory sections - in between the stack and the program space  #define X300_FW_SHMEM_BASE 0x6000 diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp index 1e424414e..0483ecf11 100644 --- a/host/lib/usrp/x300/x300_impl.cpp +++ b/host/lib/usrp/x300/x300_impl.cpp @@ -47,23 +47,38 @@ using namespace uhd;  using namespace uhd::usrp;  using namespace uhd::transport;  using namespace uhd::niusrprio; +using namespace uhd::usrp::gpio_atr;  using namespace uhd::usrp::x300;  namespace asio = boost::asio; -/*********************************************************************** - * Discovery over the udp and pcie transport - **********************************************************************/ +static bool has_dram_buff(wb_iface::sptr zpu_ctrl) { +    bool dramR0 = dma_fifo_core_3000::check( +        zpu_ctrl, SR_ADDR(SET0_BASE, ZPU_SR_DRAM_FIFO0), SR_ADDR(SET0_BASE, ZPU_RB_DRAM_FIFO0)); +    bool dramR1 = dma_fifo_core_3000::check( +        zpu_ctrl, SR_ADDR(SET0_BASE, ZPU_SR_DRAM_FIFO1), SR_ADDR(SET0_BASE, ZPU_RB_DRAM_FIFO1)); +    return (dramR0 and dramR1); +} +  static std::string get_fpga_option(wb_iface::sptr zpu_ctrl) { -    //1G = {0:1G, 1:1G} w/ DRAM, HG = {0:1G, 1:10G} w/ DRAM, XG = {0:10G, 1:10G} w/ DRAM -    //HGS = {0:1G, 1:10G} w/ SRAM, XGS = {0:10G, 1:10G} w/ SRAM +    //Possible options: +    //1G  = {0:1G, 1:1G} w/ DRAM, HG  = {0:1G, 1:10G} w/ DRAM, XG  = {0:10G, 1:10G} w/ DRAM +    //1GS = {0:1G, 1:1G} w/ SRAM, HGS = {0:1G, 1:10G} w/ SRAM, XGS = {0:10G, 1:10G} w/ SRAM -    //In the default configuration, UHD does not support the HG and XG images so -    //they are never autodetected. +    std::string option;      bool eth0XG = (zpu_ctrl->peek32(SR_ADDR(SET0_BASE, ZPU_RB_ETH_TYPE0)) == 0x1);      bool eth1XG = (zpu_ctrl->peek32(SR_ADDR(SET0_BASE, ZPU_RB_ETH_TYPE1)) == 0x1); -    return (eth0XG && eth1XG) ? "XGS" : (eth1XG ? "HGS" : "1G"); +    option = (eth0XG && eth1XG) ? "XG" : (eth1XG ? "HG" : "1G"); + +    if (not has_dram_buff(zpu_ctrl)) { +        option += "S"; +    } +    return option;  } +/*********************************************************************** + * Discovery over the udp and pcie transport + **********************************************************************/ +  //@TODO: Refactor the find functions to collapse common code for ethernet and PCIe  static device_addrs_t x300_find_with_addr(const device_addr_t &hint)  { @@ -729,6 +744,36 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)      }      //////////////////////////////////////////////////////////////////// +    // DRAM FIFO initialization +    //////////////////////////////////////////////////////////////////// +    mb.has_dram_buff = has_dram_buff(mb.zpu_ctrl); +    if (mb.has_dram_buff) { +        for (size_t i = 0; i < mboard_members_t::NUM_RADIOS; i++) { +            static const size_t NUM_REGS = 8; +            mb.dram_buff_ctrl[i] = dma_fifo_core_3000::make( +                mb.zpu_ctrl, +                SR_ADDR(SET0_BASE, ZPU_SR_DRAM_FIFO0+(i*NUM_REGS)), +                SR_ADDR(SET0_BASE, ZPU_RB_DRAM_FIFO0+i)); +            mb.dram_buff_ctrl[i]->resize(X300_DRAM_FIFO_SIZE * i, X300_DRAM_FIFO_SIZE); + +            if (mb.dram_buff_ctrl[i]->ext_bist_supported()) { +                UHD_MSG(status) << boost::format("Running BIST for DRAM FIFO %d... ") % i; +                boost::uint32_t bisterr = mb.dram_buff_ctrl[i]->run_bist(); +                if (bisterr != 0) { +                    throw uhd::runtime_error(str(boost::format("DRAM FIFO BIST failed! (code: %d)\n") % bisterr)); +                } else { +                    double throughput = mb.dram_buff_ctrl[i]->get_bist_throughput(X300_BUS_CLOCK_RATE); +                    UHD_MSG(status) << (boost::format("pass (Throughput: %.1fMB/s)") % (throughput/1e6)) << std::endl; +                } +            } else { +                if (mb.dram_buff_ctrl[i]->run_bist() != 0) { +                    throw uhd::runtime_error(str(boost::format("DRAM FIFO %d BIST failed!\n") % i)); +                } +            } +        } +    } + +    ////////////////////////////////////////////////////////////////////      // setup radios      ////////////////////////////////////////////////////////////////////      this->setup_radio(mb_i, "A", dev_addr); @@ -749,15 +794,15 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)      ////////////////////////////////////////////////////////////////////      // front panel gpio      //////////////////////////////////////////////////////////////////// -    mb.fp_gpio = gpio_core_200::make(mb.radio_perifs[0].ctrl, radio::sr_addr(radio::FP_GPIO), radio::RB32_FP_GPIO); +    mb.fp_gpio = gpio_atr_3000::make(mb.radio_perifs[0].ctrl, radio::sr_addr(radio::FP_GPIO), radio::RB32_FP_GPIO);      BOOST_FOREACH(const gpio_attr_map_t::value_type attr, gpio_attr_map)      {          _tree->create<boost::uint32_t>(mb_path / "gpio" / "FP0" / attr.second)              .set(0) -            .subscribe(boost::bind(&x300_impl::set_fp_gpio, this, mb.fp_gpio, attr.first, _1)); +            .subscribe(boost::bind(&gpio_atr_3000::set_gpio_attr, mb.fp_gpio, attr.first, _1));      }      _tree->create<boost::uint32_t>(mb_path / "gpio" / "FP0" / "READBACK") -        .publish(boost::bind(&x300_impl::get_fp_gpio, this, mb.fp_gpio)); +        .publish(boost::bind(&gpio_atr_3000::read_gpio, mb.fp_gpio));      ////////////////////////////////////////////////////////////////////      // register the time keepers - only one can be the highlander @@ -930,7 +975,8 @@ void x300_impl::setup_radio(const size_t mb_i, const std::string &slot_name, con      perif.spi = spi_core_3000::make(perif.ctrl, radio::sr_addr(radio::SPI), radio::RB32_SPI);      perif.adc = x300_adc_ctrl::make(perif.spi, DB_ADC_SEN);      perif.dac = x300_dac_ctrl::make(perif.spi, DB_DAC_SEN, mb.clock->get_master_clock_rate()); -    perif.leds = gpio_core_200_32wo::make(perif.ctrl, radio::sr_addr(radio::LEDS)); +    perif.leds = gpio_atr_3000::make_write_only(perif.ctrl, radio::sr_addr(radio::LEDS)); +    perif.leds->set_atr_mode(MODE_ATR, 0xFFFFFFFF);      perif.rx_fe = rx_frontend_core_200::make(perif.ctrl, radio::sr_addr(radio::RX_FRONT));      perif.rx_fe->set_dc_offset(rx_frontend_core_200::DEFAULT_DC_OFFSET_VALUE);      perif.rx_fe->set_dc_offset_auto(rx_frontend_core_200::DEFAULT_DC_OFFSET_ENABLE); @@ -940,7 +986,10 @@ void x300_impl::setup_radio(const size_t mb_i, const std::string &slot_name, con      perif.framer = rx_vita_core_3000::make(perif.ctrl, radio::sr_addr(radio::RX_CTRL));      perif.ddc = rx_dsp_core_3000::make(perif.ctrl, radio::sr_addr(radio::RX_DSP));      perif.ddc->set_link_rate(10e9/8); //whatever -    perif.deframer = tx_vita_core_3000::make(perif.ctrl, radio::sr_addr(radio::TX_CTRL)); +    //The DRAM FIFO is treated as in internal radio FIFO for flow control purposes +    tx_vita_core_3000::fc_monitor_loc fc_loc = +        mb.has_dram_buff ? tx_vita_core_3000::FC_PRE_FIFO : tx_vita_core_3000::FC_PRE_RADIO; +    perif.deframer = tx_vita_core_3000::make(perif.ctrl, radio::sr_addr(radio::TX_CTRL), fc_loc);      perif.duc = tx_dsp_core_3000::make(perif.ctrl, radio::sr_addr(radio::TX_DSP));      perif.duc->set_link_rate(10e9/8); //whatever @@ -1014,7 +1063,7 @@ void x300_impl::setup_radio(const size_t mb_i, const std::string &slot_name, con      //create a new dboard interface      x300_dboard_iface_config_t db_config; -    db_config.gpio = gpio_core_200::make(perif.ctrl, radio::sr_addr(radio::GPIO), radio::RB32_GPIO); +    db_config.gpio = db_gpio_atr_3000::make(perif.ctrl, radio::sr_addr(radio::GPIO), radio::RB32_GPIO);      db_config.spi = perif.spi;      db_config.rx_spi_slaveno = DB_RX_SEN;      db_config.tx_spi_slaveno = DB_TX_SEN; @@ -1143,7 +1192,7 @@ x300_impl::both_xports_t x300_impl::make_transport(           * connection type.*/          size_t eth_data_rec_frame_size = 0; -        if (mb.loaded_fpga_image == "HGS") { +        if (mb.loaded_fpga_image.substr(0,2) == "HG") {              if (mb.router_dst_here == X300_XB_DST_E0) {                  eth_data_rec_frame_size = X300_1GE_DATA_FRAME_MAX_SIZE;                  _tree->access<double>("/mboards/"+boost::lexical_cast<std::string>(mb_index) / "link_max_rate").set(X300_MAX_RATE_1GIGE); @@ -1151,7 +1200,7 @@ x300_impl::both_xports_t x300_impl::make_transport(                  eth_data_rec_frame_size = X300_10GE_DATA_FRAME_MAX_SIZE;                  _tree->access<double>("/mboards/"+boost::lexical_cast<std::string>(mb_index) / "link_max_rate").set(X300_MAX_RATE_10GIGE);              } -        } else if (mb.loaded_fpga_image == "XGS") { +        } else if (mb.loaded_fpga_image.substr(0,2) == "XG") {              eth_data_rec_frame_size = X300_10GE_DATA_FRAME_MAX_SIZE;              _tree->access<double>("/mboards/"+boost::lexical_cast<std::string>(mb_index) / "link_max_rate").set(X300_MAX_RATE_10GIGE);          } @@ -1295,16 +1344,16 @@ boost::uint32_t x300_impl::allocate_sid(mboard_members_t &mb, const sid_config_t      return sid;  } -void x300_impl::update_atr_leds(gpio_core_200_32wo::sptr leds, const std::string &rx_ant) +void x300_impl::update_atr_leds(gpio_atr_3000::sptr leds, const std::string &rx_ant)  {      const bool is_txrx = (rx_ant == "TX/RX");      const int rx_led = (1 << 2);      const int tx_led = (1 << 1);      const int txrx_led = (1 << 0); -    leds->set_atr_reg(dboard_iface::ATR_REG_IDLE, 0); -    leds->set_atr_reg(dboard_iface::ATR_REG_RX_ONLY, is_txrx? txrx_led : rx_led); -    leds->set_atr_reg(dboard_iface::ATR_REG_TX_ONLY, tx_led); -    leds->set_atr_reg(dboard_iface::ATR_REG_FULL_DUPLEX, rx_led | tx_led); +    leds->set_atr_reg(ATR_REG_IDLE, 0); +    leds->set_atr_reg(ATR_REG_RX_ONLY, is_txrx? txrx_led : rx_led); +    leds->set_atr_reg(ATR_REG_TX_ONLY, tx_led); +    leds->set_atr_reg(ATR_REG_FULL_DUPLEX, rx_led | tx_led);  }  void x300_impl::set_tick_rate(mboard_members_t &mb, const double rate) @@ -1314,7 +1363,6 @@ void x300_impl::set_tick_rate(mboard_members_t &mb, const double rate)          perif.time64->set_tick_rate(rate);          perif.framer->set_tick_rate(rate);          perif.ddc->set_tick_rate(rate); -        perif.deframer->set_tick_rate(rate);          perif.duc->set_tick_rate(rate);      }  } @@ -1509,30 +1557,6 @@ void x300_impl::set_mb_eeprom(i2c_iface::sptr i2c, const mboard_eeprom_t &mb_eep  }  /*********************************************************************** - * front-panel GPIO - **********************************************************************/ - -boost::uint32_t x300_impl::get_fp_gpio(gpio_core_200::sptr gpio) -{ -    return boost::uint32_t(gpio->read_gpio(dboard_iface::UNIT_RX)); -} - -void x300_impl::set_fp_gpio(gpio_core_200::sptr gpio, const gpio_attr_t attr, const boost::uint32_t value) -{ -    switch (attr) -    { -    case GPIO_CTRL:   return gpio->set_pin_ctrl(dboard_iface::UNIT_RX, value); -    case GPIO_DDR:    return gpio->set_gpio_ddr(dboard_iface::UNIT_RX, value); -    case GPIO_OUT:    return gpio->set_gpio_out(dboard_iface::UNIT_RX, value); -    case GPIO_ATR_0X: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, value); -    case GPIO_ATR_RX: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY, value); -    case GPIO_ATR_TX: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY, value); -    case GPIO_ATR_XX: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, value); -    default:        UHD_THROW_INVALID_CODE_PATH(); -    } -} - -/***********************************************************************   * claimer logic   **********************************************************************/ diff --git a/host/lib/usrp/x300/x300_impl.hpp b/host/lib/usrp/x300/x300_impl.hpp index 1630047af..521ce8a0e 100644 --- a/host/lib/usrp/x300/x300_impl.hpp +++ b/host/lib/usrp/x300/x300_impl.hpp @@ -41,7 +41,8 @@  #include "radio_ctrl_core_3000.hpp"  #include "rx_frontend_core_200.hpp"  #include "tx_frontend_core_200.hpp" -#include "gpio_core_200.hpp" +#include "gpio_atr_3000.hpp" +#include "dma_fifo_core_3000.hpp"  #include <boost/weak_ptr.hpp>  #include <uhd/usrp/gps_ctrl.hpp>  #include <uhd/usrp/mboard_eeprom.hpp> @@ -56,8 +57,11 @@ static const std::string X300_FW_FILE_NAME  = "usrp_x300_fw.bin";  static const double X300_DEFAULT_TICK_RATE      = 200e6;        //Hz  static const double X300_BUS_CLOCK_RATE         = 166.666667e6; //Hz -static const size_t X300_TX_HW_BUFF_SIZE        = 520*1024;      //512K SRAM buffer + 8K 2Clk FIFO -static const size_t X300_TX_FC_RESPONSE_FREQ    = 8;            //per flow-control window +static const size_t X300_TX_HW_BUFF_SIZE_SRAM       = 520*1024;      //512K SRAM buffer + 8K 2Clk FIFO +static const size_t X300_TX_FC_RESPONSE_FREQ_SRAM   = 8;             //per flow-control window +static const size_t X300_TX_HW_BUFF_SIZE_DRAM       = 128*1024; +static const size_t X300_TX_FC_RESPONSE_FREQ_DRAM   = 32; +static const boost::uint32_t X300_DRAM_FIFO_SIZE    = 32*1024*1024;  static const size_t X300_RX_SW_BUFF_SIZE_ETH        = 0x2000000;//32MiB    For an ~8k frame size any size >32MiB is just wasted buffer space  static const size_t X300_RX_SW_BUFF_SIZE_ETH_MACOS  = 0x100000; //1Mib @@ -123,7 +127,7 @@ enum  struct x300_dboard_iface_config_t  { -    gpio_core_200::sptr gpio; +    uhd::usrp::gpio_atr::db_gpio_atr_3000::sptr gpio;      spi_core_3000::sptr spi;      size_t rx_spi_slaveno;      size_t tx_spi_slaveno; @@ -185,7 +189,7 @@ private:          rx_dsp_core_3000::sptr ddc;          tx_vita_core_3000::sptr deframer;          tx_dsp_core_3000::sptr duc; -        gpio_core_200_32wo::sptr leds; +        uhd::usrp::gpio_atr::gpio_atr_3000::sptr leds;          rx_frontend_core_200::sptr rx_fe;          tx_frontend_core_200::sptr tx_fe;          //Registers @@ -226,10 +230,14 @@ private:               return slot_name == "A" ? 0 : 1;          } +        bool has_dram_buff; +        dma_fifo_core_3000::sptr dram_buff_ctrl[NUM_RADIOS]; + +          //other perifs on mboard          x300_clock_ctrl::sptr clock;          uhd::gps_ctrl::sptr gps; -        gpio_core_200::sptr fp_gpio; +        uhd::usrp::gpio_atr::gpio_atr_3000::sptr fp_gpio;          uhd::usrp::x300::fw_regmap_t::sptr fw_regmap; @@ -365,9 +373,7 @@ private:      void check_fw_compat(const uhd::fs_path &mb_path, uhd::wb_iface::sptr iface);      void check_fpga_compat(const uhd::fs_path &mb_path, const mboard_members_t &members); -    void update_atr_leds(gpio_core_200_32wo::sptr, const std::string &ant); -    boost::uint32_t get_fp_gpio(gpio_core_200::sptr); -    void set_fp_gpio(gpio_core_200::sptr, const gpio_attr_t, const boost::uint32_t); +    void update_atr_leds(uhd::usrp::gpio_atr::gpio_atr_3000::sptr, const std::string &ant);      void self_cal_adc_capture_delay(mboard_members_t& mb, const size_t radio_i, bool print_status = false);      double self_cal_adc_xfer_delay(mboard_members_t& mb, bool apply_delay = false); diff --git a/host/lib/usrp/x300/x300_io_impl.cpp b/host/lib/usrp/x300/x300_io_impl.cpp index e3515af0c..1356daec5 100644 --- a/host/lib/usrp/x300/x300_io_impl.cpp +++ b/host/lib/usrp/x300/x300_io_impl.cpp @@ -216,9 +216,10 @@ struct x300_tx_fc_guts_t   * FC credit we have is C = F + M - N (i.e. we can send C more packets   * before getting another ack).   */ -static size_t get_tx_flow_control_window(size_t frame_size, const device_addr_t& tx_args) +static size_t get_tx_flow_control_window(size_t frame_size, const bool dram_buff, const device_addr_t& tx_args)  { -    double hw_buff_size = tx_args.cast<double>("send_buff_size", X300_TX_HW_BUFF_SIZE); +    double default_buff_size = dram_buff ? X300_TX_HW_BUFF_SIZE_DRAM : X300_TX_HW_BUFF_SIZE_SRAM; +    double hw_buff_size = tx_args.cast<double>("send_buff_size", default_buff_size);      size_t window_in_pkts = (static_cast<size_t>(hw_buff_size) / frame_size);      if (window_in_pkts == 0) {          throw uhd::value_error("send_buff_size must be larger than the send_frame_size."); @@ -580,8 +581,9 @@ tx_streamer::sptr x300_impl::get_tx_stream(const uhd::stream_args_t &args_)          perif.duc->setup(args);          //flow control setup -        size_t fc_window = get_tx_flow_control_window(xport.send->get_send_frame_size(), device_addr);  //In packets -        const size_t fc_handle_window = std::max<size_t>(1, fc_window/X300_TX_FC_RESPONSE_FREQ); +        size_t fc_window = get_tx_flow_control_window(xport.send->get_send_frame_size(), mb.has_dram_buff, device_addr);  //In packets +        const size_t fc_handle_window = std::max<size_t>(1, +            fc_window/ (mb.has_dram_buff ? X300_TX_FC_RESPONSE_FREQ_DRAM : X300_TX_FC_RESPONSE_FREQ_SRAM));          UHD_LOG << "TX Flow Control Window = " << fc_window << ", TX Flow Control Handler Window = " << fc_handle_window << std::endl; diff --git a/host/lib/usrp/x300/x300_regs.hpp b/host/lib/usrp/x300/x300_regs.hpp index eba30abb5..489d249ba 100644 --- a/host/lib/usrp/x300/x300_regs.hpp +++ b/host/lib/usrp/x300/x300_regs.hpp @@ -42,7 +42,7 @@ static const uint32_t TIME       = 128;  static const uint32_t RX_DSP     = 144;  static const uint32_t TX_DSP     = 184;  static const uint32_t LEDS       = 195; -static const uint32_t FP_GPIO    = 200; +static const uint32_t FP_GPIO    = 201;  static const uint32_t RX_FRONT   = 208;  static const uint32_t TX_FRONT   = 216; @@ -77,6 +77,8 @@ localparam ZPU_SR_XB_LOCAL   = 03;  localparam ZPU_SR_SPI        = 32;  localparam ZPU_SR_ETHINT0    = 40;  localparam ZPU_SR_ETHINT1    = 56; +localparam ZPU_SR_DRAM_FIFO0 = 72; +localparam ZPU_SR_DRAM_FIFO1 = 80;  //reset bits  #define ZPU_SR_SW_RST_ETH_PHY           (1<<0) @@ -89,6 +91,8 @@ localparam ZPU_RB_CLK_STATUS = 3;  localparam ZPU_RB_COMPAT_NUM = 6;  localparam ZPU_RB_ETH_TYPE0  = 4;  localparam ZPU_RB_ETH_TYPE1  = 5; +localparam ZPU_RB_DRAM_FIFO0 = 10; +localparam ZPU_RB_DRAM_FIFO1 = 11;  //spi slaves on radio  #define DB_DAC_SEN      (1 << 7) diff --git a/host/lib/usrp_clock/octoclock/CMakeLists.txt b/host/lib/usrp_clock/octoclock/CMakeLists.txt index a74cb034f..d3728344e 100644 --- a/host/lib/usrp_clock/octoclock/CMakeLists.txt +++ b/host/lib/usrp_clock/octoclock/CMakeLists.txt @@ -18,8 +18,6 @@  ########################################################################  # Conditionally configure the OctoClock support  ######################################################################## -LIBUHD_REGISTER_COMPONENT("OctoClock" ENABLE_OCTOCLOCK ON "ENABLE_LIBUHD" OFF OFF) -  IF(ENABLE_OCTOCLOCK)      ADD_DEFINITIONS(-DIHEX_USE_STDBOOL) diff --git a/host/lib/utils/msg.cpp b/host/lib/utils/msg.cpp index de98ada64..95879a116 100644 --- a/host/lib/utils/msg.cpp +++ b/host/lib/utils/msg.cpp @@ -79,6 +79,8 @@ void uhd::msg::register_handler(const handler_t &handler){  }  static void default_msg_handler(uhd::msg::type_t type, const std::string &msg){ +    static boost::mutex msg_mutex; +    boost::mutex::scoped_lock lock(msg_mutex);      switch(type){      case uhd::msg::fastpath:          std::cerr << msg << std::flush; diff --git a/host/lib/utils/paths.cpp b/host/lib/utils/paths.cpp index eb9e69a49..5aa505baf 100644 --- a/host/lib/utils/paths.cpp +++ b/host/lib/utils/paths.cpp @@ -17,7 +17,6 @@  #include <uhd/config.hpp>  #include <uhd/exception.hpp> -#include <uhd/transport/nirio/nifpga_lvbitx.h>  #include <uhd/utils/paths.hpp>  #include <boost/algorithm/string.hpp> diff --git a/host/tests/CMakeLists.txt b/host/tests/CMakeLists.txt index 8b12c961f..d5d15ede8 100644 --- a/host/tests/CMakeLists.txt +++ b/host/tests/CMakeLists.txt @@ -77,3 +77,5 @@ IF(MSVC OR APPLE OR LINUX)      ADD_LIBRARY(module_test MODULE module_test.cpp)      TARGET_LINK_LIBRARIES(module_test uhd)  ENDIF() + +ADD_SUBDIRECTORY(devtest) diff --git a/host/tests/convert_test.cpp b/host/tests/convert_test.cpp index d71d756dd..8d359d2e2 100644 --- a/host/tests/convert_test.cpp +++ b/host/tests/convert_test.cpp @@ -417,16 +417,16 @@ BOOST_AUTO_TEST_CASE(test_convert_types_sc16_and_sc8){  }  /*********************************************************************** - * Test short conversion + * Test u8 conversion   **********************************************************************/  static void test_convert_types_u8(      size_t nsamps, convert::id_type &id  ){      //fill the input samples      std::vector<boost::uint8_t> input(nsamps), output(nsamps); -    //BOOST_FOREACH(boost::uint8_t &in, input) in = boost::uint8_t(std::rand() & 0xFF); -    boost::uint32_t d = 48; -    BOOST_FOREACH(boost::uint8_t &in, input) in = d++; +    BOOST_FOREACH(boost::uint8_t &in, input) in = boost::uint8_t(std::rand() & 0xFF); +    //boost::uint32_t d = 48; +    //BOOST_FOREACH(boost::uint8_t &in, input) in = d++;      //run the loopback and test      convert::id_type in_id = id; @@ -455,3 +455,158 @@ BOOST_AUTO_TEST_CASE(test_convert_types_u8_and_u8){          test_convert_types_u8(nsamps, id);      }  } + +/*********************************************************************** + * Test s8 conversion + **********************************************************************/ +static void test_convert_types_s8( +    size_t nsamps, convert::id_type &id +){ +    //fill the input samples +    std::vector<boost::int8_t> input(nsamps), output(nsamps); +    BOOST_FOREACH(boost::int8_t &in, input) in = boost::int8_t(std::rand() & 0xFF); + +    //run the loopback and test +    convert::id_type in_id = id; +    convert::id_type out_id = id; +    std::swap(out_id.input_format, out_id.output_format); +    std::swap(out_id.num_inputs, out_id.num_outputs); +    loopback(nsamps, in_id, out_id, input, output); +    BOOST_CHECK_EQUAL_COLLECTIONS(input.begin(), input.end(), output.begin(), output.end()); +} + +BOOST_AUTO_TEST_CASE(test_convert_types_s8_and_s8){ +    convert::id_type id; +    id.input_format = "s8"; +    id.num_inputs = 1; +    id.num_outputs = 1; + +    //try various lengths to test edge cases +    id.output_format = "s8_item32_le"; +    for (size_t nsamps = 1; nsamps < 16; nsamps++){ +        test_convert_types_s8(nsamps, id); +    } + +    //try various lengths to test edge cases +    id.output_format = "s8_item32_be"; +    for (size_t nsamps = 1; nsamps < 16; nsamps++){ +        test_convert_types_s8(nsamps, id); +    } +} + +/*********************************************************************** + * Test s16 conversion + **********************************************************************/ +static void test_convert_types_s16( +    size_t nsamps, convert::id_type &id +){ +    //fill the input samples +    std::vector<boost::int16_t> input(nsamps), output(nsamps); +    BOOST_FOREACH(boost::int16_t &in, input) in = boost::int16_t(std::rand() & 0xFFFF); + +    //run the loopback and test +    convert::id_type in_id = id; +    convert::id_type out_id = id; +    std::swap(out_id.input_format, out_id.output_format); +    std::swap(out_id.num_inputs, out_id.num_outputs); +    loopback(nsamps, in_id, out_id, input, output); +    BOOST_CHECK_EQUAL_COLLECTIONS(input.begin(), input.end(), output.begin(), output.end()); +} + +BOOST_AUTO_TEST_CASE(test_convert_types_s16_and_s16){ +    convert::id_type id; +    id.input_format = "s16"; +    id.num_inputs = 1; +    id.num_outputs = 1; + +    //try various lengths to test edge cases +    id.output_format = "s16_item32_le"; +    for (size_t nsamps = 1; nsamps < 16; nsamps++){ +        test_convert_types_s16(nsamps, id); +    } + +    //try various lengths to test edge cases +    id.output_format = "s16_item32_be"; +    for (size_t nsamps = 1; nsamps < 16; nsamps++){ +        test_convert_types_s16(nsamps, id); +    } +} + +/*********************************************************************** + * Test fc32 -> fc32 conversion + **********************************************************************/ +static void test_convert_types_fc32( +    size_t nsamps, convert::id_type &id +){ +    //fill the input samples +    std::vector< std::complex<float> > input(nsamps), output(nsamps); +    BOOST_FOREACH(fc32_t &in, input) in = fc32_t( +        (std::rand()/float(RAND_MAX/2)) - 1, +        (std::rand()/float(RAND_MAX/2)) - 1 +    ); + +    //run the loopback and test +    convert::id_type in_id = id; +    convert::id_type out_id = id; +    std::swap(out_id.input_format, out_id.output_format); +    std::swap(out_id.num_inputs, out_id.num_outputs); +    loopback(nsamps, in_id, out_id, input, output); +    BOOST_CHECK_EQUAL_COLLECTIONS(input.begin(), input.end(), output.begin(), output.end()); +} + +BOOST_AUTO_TEST_CASE(test_convert_types_fc32_and_fc32){ +    convert::id_type id; +    id.input_format = "fc32"; +    id.num_inputs = 1; +    id.num_outputs = 1; + +    //try various lengths to test edge cases +    id.output_format = "fc32_item32_le"; +    for (size_t nsamps = 1; nsamps < 16; nsamps++){ +        test_convert_types_fc32(nsamps, id); +    } + +    //try various lengths to test edge cases +    id.output_format = "fc32_item32_be"; +    for (size_t nsamps = 1; nsamps < 16; nsamps++){ +        test_convert_types_fc32(nsamps, id); +    } +} + +/*********************************************************************** + * Test f32 -> f32 conversion + **********************************************************************/ +static void test_convert_types_f32( +    size_t nsamps, convert::id_type &id +){ +    //fill the input samples +    std::vector<float> input(nsamps), output(nsamps); +    BOOST_FOREACH(float &in, input) in = float((std::rand()/float(RAND_MAX/2)) - 1); + +    //run the loopback and test +    convert::id_type in_id = id; +    convert::id_type out_id = id; +    std::swap(out_id.input_format, out_id.output_format); +    std::swap(out_id.num_inputs, out_id.num_outputs); +    loopback(nsamps, in_id, out_id, input, output); +    BOOST_CHECK_EQUAL_COLLECTIONS(input.begin(), input.end(), output.begin(), output.end()); +} + +BOOST_AUTO_TEST_CASE(test_convert_types_f32_and_f32){ +    convert::id_type id; +    id.input_format = "f32"; +    id.num_inputs = 1; +    id.num_outputs = 1; + +    //try various lengths to test edge cases +    id.output_format = "f32_item32_le"; +    for (size_t nsamps = 1; nsamps < 16; nsamps++){ +        test_convert_types_f32(nsamps, id); +    } + +    //try various lengths to test edge cases +    id.output_format = "f32_item32_be"; +    for (size_t nsamps = 1; nsamps < 16; nsamps++){ +        test_convert_types_f32(nsamps, id); +    } +} diff --git a/host/tests/devtest/CMakeLists.txt b/host/tests/devtest/CMakeLists.txt new file mode 100644 index 000000000..6fa921bbd --- /dev/null +++ b/host/tests/devtest/CMakeLists.txt @@ -0,0 +1,58 @@ +# +# 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/>. +# + +# Formatting +MESSAGE(STATUS "") + +# All devtest files get installed: +FILE(GLOB py_devtest_files "*.py") +UHD_INSTALL(PROGRAMS +    ${py_devtest_files} +    DESTINATION ${PKG_LIB_DIR}/tests/devtest +    COMPONENT tests +) + +# Arguments: +# - pattern: This will be used to identify which devtest_*.py is to be executed. +# - filter: Will be used in args strings as "type=<filter>". +# - devtype: A descriptive string. Is only used for CMake output. +MACRO(ADD_DEVTEST pattern filter devtype) +    MESSAGE(STATUS "Adding ${devtype} device test target") +    ADD_CUSTOM_TARGET("test_${pattern}" +        ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/run_testsuite.py +        "--src-dir" "${CMAKE_CURRENT_SOURCE_DIR}" +        "--devtest-pattern" "${pattern}" +        "--device-filter" "${filter}" +        "--build-type" "${CMAKE_BUILD_TYPE}" +        "--build-dir" "${CMAKE_BINARY_DIR}" +        COMMENT "Running device test on all connected ${devtype} devices:" +        WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" +    ) +ENDMACRO(ADD_DEVTEST) + +IF(ENABLE_B200) +    ADD_DEVTEST("b2xx" "b200" "B2XX") +ENDIF(ENABLE_B200) +IF(ENABLE_X300) +    ADD_DEVTEST("x3x0" "x300" "X3x0") +ENDIF(ENABLE_X300) +IF(ENABLE_E300) +    ADD_DEVTEST("e3xx" "e3x0" "E3XX") +ENDIF(ENABLE_E300) + +# Formatting +MESSAGE(STATUS "") diff --git a/host/tests/devtest/README.md b/host/tests/devtest/README.md new file mode 100644 index 000000000..ee1ff3c9f --- /dev/null +++ b/host/tests/devtest/README.md @@ -0,0 +1,28 @@ +# Device Tests + +These are a set of tests to be run with one or more attached devices. +None of these tests require special configuration; e.g., the X3x0 test +will work regardless of attached daughterboards, FPGIO wiring etc. + +## Adding new tests + +To add new tests, add new files with classes that derive from unittest.TestCase. +Most of the time, you'll want to derive from `uhd_test_case` or +`uhd_example_test_case`. + +## Adding new devices + +To add new devices, follow these steps: + +1) Add an entry to the CMakeLists.txt file in this directory using the +   `ADD_DEVTEST()` macro. +2) Add a `devtest_pattern.py` file to this directory, where `pattern` is +   the same pattern used in the `ADD_DEVTEST()` macro. +3) Edit this devtest file to import all the tests you want to run. Some +   may require parameterization. + +The devtest file is 'executed' using Python's unittest module, so it doesn't +require any actual commands. If the device needs special initialization, +commands inside this file will be executed *if* they are *not* in a +`if __name__ == "__main__"` conditional. + diff --git a/host/tests/devtest/benchmark_rate_test.py b/host/tests/devtest/benchmark_rate_test.py new file mode 100755 index 000000000..2602e1771 --- /dev/null +++ b/host/tests/devtest/benchmark_rate_test.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python +# +# 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/>. +# +""" Test using benchmark_rate. """ + +import re +from uhd_test_base import shell_application, uhd_example_test_case + +class uhd_benchmark_rate_test(uhd_example_test_case): +    """ +    Run benchmark_rate in various configurations. +    """ +    tests = {} + +    def setup_example(self): +        """ +        Set args. +        """ +        self.test_params = uhd_benchmark_rate_test.tests + +    def run_test(self, test_name, test_args): +        """ +        Runs benchmark_rate with the given parameters. Parses output and writes +        results to file. +        """ +        self.log.info('Running test {n}, Channel = {c}, Sample Rate = {r}'.format( +            n=test_name, c=test_args.get('chan', '0'), r=test_args.get('rate', 1e6), +        )) +        args = [ +            self.create_addr_args_str(), +            '--duration', str(test_args.get('duration', 1)), +            '--channels', str(test_args.get('chan', '0')), +        ] +        if 'tx' in test_args['direction']: +            args.append('--tx_rate') +            args.append(str(test_args.get('rate', 1e6))) +        if 'rx' in test_args['direction']: +            args.append('--rx_rate') +            args.append(str(test_args.get('rate'))) +        (app, run_results) = self.run_example('benchmark_rate', args) +        match = re.search(r'(Num received samples):\s*(.*)', app.stdout) +        run_results['num_rx_samples'] = int(match.group(2)) if match else -1 +        match = re.search(r'(Num dropped samples):\s*(.*)', app.stdout) +        run_results['num_rx_dropped'] = int(match.group(2)) if match else -1 +        match = re.search(r'(Num overflows detected):\s*(.*)', app.stdout) +        run_results['num_rx_overruns'] = int(match.group(2)) if match else -1 +        match = re.search(r'(Num transmitted samples):\s*(.*)', app.stdout) +        run_results['num_tx_samples'] = int(match.group(2)) if match else -1 +        match = re.search(r'(Num sequence errors):\s*(.*)', app.stdout) +        run_results['num_tx_seqerrs'] = int(match.group(2)) if match else -1 +        match = re.search(r'(Num underflows detected):\s*(.*)', app.stdout) +        run_results['num_tx_underruns'] = int(match.group(2)) if match else -1 +        run_results['passed'] = all([ +            run_results['return_code'] == 0, +            run_results['num_rx_dropped'] == 0, +            run_results['num_tx_seqerrs'] == 0, +            run_results['num_tx_underruns'] <= test_args.get('acceptable-underruns', 0), +        ]) +        self.report_example_results(test_name, run_results) +        return run_results + diff --git a/host/tests/devtest/devtest_b2xx.py b/host/tests/devtest/devtest_b2xx.py new file mode 100755 index 000000000..da358d08e --- /dev/null +++ b/host/tests/devtest/devtest_b2xx.py @@ -0,0 +1,76 @@ +# +# 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/>. +# +""" +Run device tests for the B2xx series. +""" +from usrp_probe_test import uhd_usrp_probe_test +from benchmark_rate_test import uhd_benchmark_rate_test +uhd_benchmark_rate_test.tests = { +    #'mimo': { +        #'duration': 1, +        #'directions': ['tx,rx',], +        #'channels': ['0,1',], +        #'sample-rates': [1e6, 30e6], +        #'products': ['B210',], +        #'acceptable-underruns': 500, +    #}, +    'siso_chan0_slow': { +        'duration': 1, +        'direction': 'tx,rx', +        'chan': '0', +        'rate': 1e6, +        'acceptable-underruns': 50, +    }, +    'siso_chan0_fast': { +        'duration': 1, +        'direction': 'tx,rx', +        'chan': '0', +        'rate': 40e6, +        'acceptable-underruns': 500, +    }, +    'siso_chan1_slow': { +        'duration': 1, +        'direction': 'tx,rx', +        'chan': '1', +        'rate': 1e6, +        'acceptable-underruns': 50, +        'products': ['B210',], +    }, +    'siso_chan1_fast': { +        'duration': 1, +        'direction': 'tx,rx', +        'chan': '1', +        'rate': 40e6, +        'acceptable-underruns': 500, +        'products': ['B210',], +    }, +} + +from rx_samples_to_file_test import rx_samples_to_file_test +rx_samples_to_file_test.tests = { +    'default': { +        'duration': 1, +        'subdev': 'A:A', +        'rate': 5e6, +        'products': ['B210', 'B200',], +    }, +} + +from tx_bursts_test import uhd_tx_bursts_test +from test_pps_test import uhd_test_pps_test +from gpio_test import gpio_test + diff --git a/host/tests/devtest/devtest_e3xx.py b/host/tests/devtest/devtest_e3xx.py new file mode 100755 index 000000000..1cab44184 --- /dev/null +++ b/host/tests/devtest/devtest_e3xx.py @@ -0,0 +1,58 @@ +# +# 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/>. +# +""" +Run device tests for the E3XX series. +""" +from usrp_probe_test import uhd_usrp_probe_test +from benchmark_rate_test import uhd_benchmark_rate_test +uhd_benchmark_rate_test.tests = { +    'mimo': { +        'duration': 1, +        'direction': 'tx,rx', +        'channels': '0,1', +        'rate': 1e6, +        'acceptable-underruns': 500, +    }, +    'siso_chan0_slow': { +        'duration': 1, +        'direction': 'tx,rx', +        'chan': '0', +        'rate': 1e6, +        'acceptable-underruns': 50, +    }, +    'siso_chan1_slow': { +        'duration': 1, +        'direction': 'tx,rx', +        'chan': '1', +        'rate': 1e6, +        'acceptable-underruns': 50, +        'products': ['B210',], +    }, +} + +from rx_samples_to_file_test import rx_samples_to_file_test +rx_samples_to_file_test.tests = { +    'default': { +        'duration': 1, +        'subdev': 'A:A', +        'rate': 5e6, +    }, +} + +from tx_bursts_test import uhd_tx_bursts_test +from test_pps_test import uhd_test_pps_test + diff --git a/host/tests/devtest/devtest_x3x0.py b/host/tests/devtest/devtest_x3x0.py new file mode 100755 index 000000000..7ad6b21b6 --- /dev/null +++ b/host/tests/devtest/devtest_x3x0.py @@ -0,0 +1,57 @@ +# +# 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/>. +# +""" +Run device tests for the X3x0 series. +""" + +from benchmark_rate_test import uhd_benchmark_rate_test +uhd_benchmark_rate_test.tests = { +    'mimo_slow': { +        'duration': 1, +        'direction': 'tx,rx', +        'chan': '0,1', +        'rate': 1e6, +        'acceptable-underruns': 500, +    }, +    'mimo_fast': { +        'duration': 1, +        'direction': 'tx,rx', +        'chan': '0,1', +        'rate': 12.5e6, +        'acceptable-underruns': 500, +    }, +    'siso_chan0_slow': { +        'duration': 1, +        'direction': 'tx,rx', +        'chan': '0', +        'rate': 1e6, +        'acceptable-underruns': 0, +    }, +    'siso_chan1_slow': { +        'duration': 1, +        'direction': 'tx,rx', +        'chan': '1', +        'rate': 1e6, +        'acceptable-underruns': 0, +    }, +} + +#from rx_samples_to_file_test import rx_samples_to_file_test +from tx_bursts_test import uhd_tx_bursts_test +from test_pps_test import uhd_test_pps_test +from gpio_test import gpio_test + diff --git a/host/tests/devtest/gpio_test.py b/host/tests/devtest/gpio_test.py new file mode 100755 index 000000000..d764a8d96 --- /dev/null +++ b/host/tests/devtest/gpio_test.py @@ -0,0 +1,47 @@ +# +# 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/>. +# +""" Test for test_pps_input. """ + +import re +from uhd_test_base import uhd_example_test_case + +class gpio_test(uhd_example_test_case): +    """ Run gpio. """ +    tests = {'default': {},} + +    def setup_example(self): +        """ +        Set args. +        """ +        self.test_params = gpio_test.tests + +    def run_test(self, test_name, test_args): +        """ Run the app and scrape for the success message. """ +        self.log.info('Running test {n}'.format(n=test_name,)) +        # Run example: +        args = [ +            self.create_addr_args_str(), +        ] +        (app, run_results) = self.run_example('gpio', args) +        # Evaluate pass/fail: +        run_results['passed'] = all([ +            app.returncode == 0, +            re.search('All tests passed!', app.stdout) is not None, +        ]) +        self.report_example_results(test_name, run_results) +        return run_results + diff --git a/host/tests/devtest/run_testsuite.py b/host/tests/devtest/run_testsuite.py new file mode 100755 index 000000000..30601c8bd --- /dev/null +++ b/host/tests/devtest/run_testsuite.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python +# +# 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/>. +# +""" +Device test runner. +""" + +import os +import sys +import subprocess +import argparse +import logging +import time +from threading  import Thread +try: +    from Queue import Queue, Empty +except ImportError: +    from queue import Queue, Empty  # Py3k +from usrp_probe import get_usrp_list + +ANI = ('.', 'o', 'O', '0', 'O', 'o') + +def setup_parser(): +    """ Set up argparser """ +    parser = argparse.ArgumentParser(description="Test utility for UHD/USRP.") +    parser.add_argument('--devtest-pattern', '-p', default='*', help='e.g. b2xx') +    parser.add_argument('--device-filter', '-f', default=None, required=True, help='b200, x300, ...') +    parser.add_argument('--log-dir', '-l', default='.') +    parser.add_argument('--src-dir', default='.', help='Directory where the test sources are stored') +    parser.add_argument('--build-dir', default=None, help='Build dir (where examples/ and utils/ are)') +    parser.add_argument('--build-type', default='Release') +    return parser + +def setup_env(args): +    def setup_env_win(env, build_dir, build_type): +        env['PATH'] = "{build_dir}/lib/{build_type};{build_dir}/examples/{build_type};{build_dir}/utils/{build_type};{path}".format( +            build_dir=build_dir, build_type=build_type, path=env.get('PATH', '') +        ) +        env['LIBPATH'] = "{build_dir}/lib/{build_type};{path}".format( +            build_dir=build_dir, build_type=build_type, path=env.get('LIBPATH', '') +        ) +        env['LIB'] = "{build_dir}/lib/{build_type};{path}".format( +            build_dir=build_dir, build_type=build_type, path=env.get('LIB', '') +        ) +        return env +    def setup_env_unix(env, build_dir): +        env['PATH'] = "{build_dir}/examples:{build_dir}/utils:{path}".format( +            build_dir=build_dir, path=env.get('PATH', '') +        ) +        env['LD_LIBRARY_PATH'] = "{build_dir}/lib:{path}".format( +            build_dir=build_dir, path=env.get('LD_LIBRARY_PATH', '') +        ) +        return env +    def setup_env_osx(env, build_dir): +        env['PATH'] = "{build_dir}/examples:{build_dir}/utils:{path}".format( +                build_dir=build_dir, path=env.get('PATH', '') +        ) +        env['DYLD_LIBRARY_PATH'] = "{build_dir}/lib:{path}".format( +                build_dir=build_dir, path=env.get('DYLD_LIBRARY_PATH', '') +        ) +        return env +    ### Go +    env = os.environ +    if sys.platform.startswith('linux'): +        env = setup_env_unix(env, args.build_dir) +    elif sys.platform.startswith('win'): +        env = setup_env_win(env, args.build_dir, args.build_type) +    elif sys.platform.startswith('darwin'): +        env = setup_env_osx(env, args.build_dir) +    else: +        print("Devtest not supported on this platform ({0}).".format(sys.platform)) +        exit(1) +    return env + +def main(): +    """ +    Go, go, go! +    """ +    args = setup_parser().parse_args() +    devtest_pattern = "devtest_{p}.py".format(p=args.devtest_pattern) +    uhd_args_list = get_usrp_list("type=" + args.device_filter) +    if len(uhd_args_list) == 0: +        print("No devices found. Exiting.") +        exit(1) +    tests_passed = True +    for uhd_idx, uhd_info in enumerate(uhd_args_list): +        print('--- Running all tests for device {dev} ({prod}, Serial: {ser}).'.format( +            dev=uhd_idx, +            prod=uhd_info.get('product', 'USRP'), +            ser=uhd_info.get('serial') +        )) +        print('--- This will take some time. Better grab a cup of tea.') +        env = setup_env(args) +        args_str = uhd_info['args'] +        env['_UHD_TEST_ARGS_STR'] = args_str +        logfile_name = "log{}.log".format( +            args_str.replace('type=', '_').replace('serial=', '_').replace(',', '') +        ) +        resultsfile_name = "results{}.log".format( +            args_str.replace('type=', '_').replace('serial=', '_').replace(',', '') +        ) +        env['_UHD_TEST_LOGFILE'] = os.path.join(args.log_dir, logfile_name) +        env['_UHD_TEST_RESULTSFILE'] = os.path.join(args.log_dir, resultsfile_name) +        env['_UHD_TEST_LOG_LEVEL'] = str(logging.INFO) +        env['_UHD_TEST_PRINT_LEVEL'] = str(logging.WARNING) +        p = subprocess.Popen( +            [ +                "python", "-m", "unittest", "discover", "-v", +                "-s", args.src_dir, +                "-p", devtest_pattern, +            ], +            env=env, +            stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, +        ) +        print(p.communicate()[0]) +        if p.returncode != 0: +            tests_passed = False +    print('--- Done testing all attached devices.') +    return tests_passed + +if __name__ == "__main__": +    if not main(): +        exit(1) + diff --git a/host/tests/devtest/rx_samples_to_file_test.py b/host/tests/devtest/rx_samples_to_file_test.py new file mode 100755 index 000000000..bac6ac256 --- /dev/null +++ b/host/tests/devtest/rx_samples_to_file_test.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python +# +# 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/>. +# +""" Test the rx_samples_to_file example. """ + +from uhd_test_base import uhd_example_test_case + +class rx_samples_to_file_test(uhd_example_test_case): +    """ +    Run rx_samples_to_file and check output. +    """ +    tests = { +        'default': { +            'duration': 1, +            'rate': 5e6, +        }, +    } + +    def setup_example(self): +        """ +        Set args. +        """ +        self.test_params = rx_samples_to_file_test.tests + +    def run_test(self, test_name, test_args): +        """ +        Test launcher. Runs the example. +        """ +        self.log.info('Running test {n}, Subdev = {subdev}, Sample Rate = {rate}'.format( +            n=test_name, subdev=test_args.get('subdev'), rate=test_args.get('rate'), +        )) +        # Run example: +        args = [ +            self.create_addr_args_str(), +            '--null', +            '--stats', +            '--duration', str(test_args['duration']), +            '--rate', str(test_args.get('rate', 1e6)), +            '--wirefmt', test_args.get('wirefmt', 'sc16'), +        ] +        if test_args.has_key('subdev'): +            args.append('--subdev') +            args.append(test_args['subdev']) +        (app, run_results) = self.run_example('rx_samples_to_file', args) +        # Evaluate pass/fail: +        run_results['passed'] = all([ +            not run_results['has_D'], +            not run_results['has_S'], +            run_results['return_code'] == 0, +        ]) +        self.report_example_results(test_name, run_results) +        return run_results + diff --git a/host/tests/devtest/test_messages_test.py b/host/tests/devtest/test_messages_test.py new file mode 100644 index 000000000..496765c75 --- /dev/null +++ b/host/tests/devtest/test_messages_test.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python +# +# 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/>. +# +""" Test the test_messages example. """ + +import re +from uhd_test_base import uhd_example_test_case + +class uhd_test_messages_test(uhd_example_test_case): +    """ +    Run test_messages and check output. +    """ +    tests = {'default': {},} + +    def setup_example(self): +        """ +        Set args. +        """ +        self.test_params = uhd_test_messages_test.tests + +    def run_test(self, test_name, test_args): +        """ Run the app and scrape for the failure messages. """ +        self.log.info('Running test {n}'.format(n=test_name,)) +        # Run example: +        args = [ +            self.create_addr_args_str(), +        ] +        if test_args.has_key('ntests'): +            args.append('--ntests') +            args.append(test_args['ntests']) +        (app, run_results) = self.run_example('test_messages', args) +        # Evaluate pass/fail: +        succ_fail_re = re.compile(r'(?P<test>.*)->\s+(?P<succ>\d+) successes,\s+(?P<fail>\d+) +failures') +        for mo in succ_fail_re.finditer(app.stdout): +            key = mo.group("test").strip().replace(' ', '_').lower() +            successes = int(mo.group("succ")) +            failures = int(mo.group("fail")) +            run_results[key] = "{}/{}".format(successes, successes+failures) +            run_results['passed'] = bool(failures) + +        self.report_example_results(test_name, run_results) +        return run_results + diff --git a/host/tests/devtest/test_pps_test.py b/host/tests/devtest/test_pps_test.py new file mode 100755 index 000000000..1e5b36e2c --- /dev/null +++ b/host/tests/devtest/test_pps_test.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +# +# 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/>. +# +""" Test for test_pps_input. """ + +import re +from uhd_test_base import uhd_example_test_case + +class uhd_test_pps_test(uhd_example_test_case): +    """ Run test_pps_input. """ +    tests = {'default': {},} + +    def setup_example(self): +        """ +        Set args. +        """ +        self.test_params = uhd_test_pps_test.tests + +    def run_test(self, test_name, test_args): +        """ Run the app and scrape for the success message. """ +        self.log.info('Running test {n}'.format(n=test_name,)) +        # Run example: +        args = [ +            self.create_addr_args_str(), +        ] +        if test_args.has_key('source'): +            args.append('--source') +            args.append(test_args['source']) +        (app, run_results) = self.run_example('test_pps_input', args) +        # Evaluate pass/fail: +        run_results['passed'] = all([ +            app.returncode == 0, +            re.search('Success!', app.stdout) is not None, +        ]) +        self.report_example_results(test_name, run_results) +        return run_results + diff --git a/host/tests/devtest/tx_bursts_test.py b/host/tests/devtest/tx_bursts_test.py new file mode 100755 index 000000000..863f35fe1 --- /dev/null +++ b/host/tests/devtest/tx_bursts_test.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python +# +# 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/>. +# +""" Run the test for tx_burst """ + +import re +from uhd_test_base import uhd_example_test_case + +class uhd_tx_bursts_test(uhd_example_test_case): +    """ Run test_messages. """ +    tests = { +        'default': { +            'nsamps': 10000, +            'rate': 5e6, +            'channels': '0', +        }, +    } + +    def setup_example(self): +        """ +        Set args. +        """ +        self.test_params = uhd_tx_bursts_test.tests + +    def run_test(self, test_name, test_args): +        """ Run the app and scrape for the failure messages. """ +        self.log.info('Running test {name}, Channel = {channel}, Sample Rate = {rate}'.format( +            name=test_name, channel=test_args.get('channel'), rate=test_args.get('rate'), +        )) +        # Run example: +        args = [ +            self.create_addr_args_str(), +            '--nsamps', str(test_args['nsamps']), +            '--channels', str(test_args['channels']), +            '--rate', str(test_args.get('rate', 1e6)), +        ] +        if test_args.has_key('subdev'): +            args.append('--subdev') +            args.append(test_args['subdev']) +        (app, run_results) = self.run_example('tx_bursts', args) +        # Evaluate pass/fail: +        run_results['passed'] = all([ +            app.returncode == 0, +            not run_results['has_S'], +        ]) +        run_results['async_burst_ack_found'] = re.search('success', app.stdout) is not None +        self.report_example_results(test_name, run_results) +        return run_results + diff --git a/host/tests/devtest/uhd_test_base.py b/host/tests/devtest/uhd_test_base.py new file mode 100755 index 000000000..046e6fb47 --- /dev/null +++ b/host/tests/devtest/uhd_test_base.py @@ -0,0 +1,222 @@ +#!/usr/bin/env python + +import os +import sys +import yaml +import unittest +import re +import time +import logging +from subprocess import Popen, PIPE, STDOUT +from usrp_probe import get_usrp_list + +#-------------------------------------------------------------------------- +# Application +#-------------------------------------------------------------------------- +class shell_application(object): +    """ +    Wrapper for applications that are in $PATH. +    Note: The CMake infrastructure makes sure all examples and utils are in $PATH. +    """ +    def __init__(self, name): +        self.name = name +        self.stdout = '' +        self.stderr = '' +        self.returncode = None +        self.exec_time = None + +    def run(self, args = []): +        cmd_line = [self.name] +        cmd_line.extend(args) +        start_time = time.time() +        p = Popen(cmd_line, stdout=PIPE, stderr=PIPE, close_fds=True) +        self.stdout, self.stderr = p.communicate() +        self.returncode = p.returncode +        self.exec_time = time.time() - start_time + +#-------------------------------------------------------------------------- +# Test case base +#-------------------------------------------------------------------------- +class uhd_test_case(unittest.TestCase): +    """ +    Base class for UHD test cases. +    """ +    test_name = '--TEST--' + +    def set_up(self): +        """ +        Override this to add own setup code per test. +        """ +        pass + +    def setUp(self): +        self.name = self.__class__.__name__ +        self.test_id = self.id().split('.')[-1] +        self.results = {} +        self.results_file = os.getenv('_UHD_TEST_RESULTSFILE', "") +        if self.results_file and os.path.isfile(self.results_file): +            self.results = yaml.safe_load(open(self.results_file).read()) or {} +        self.args_str = os.getenv('_UHD_TEST_ARGS_STR', "") +        self.usrp_info = get_usrp_list(self.args_str)[0] +        if not self.results.has_key(self.usrp_info['serial']): +            self.results[self.usrp_info['serial']] = {} +        if not self.results[self.usrp_info['serial']].has_key(self.name): +            self.results[self.usrp_info['serial']][self.name] = {} +        self.setup_logger() +        self.set_up() + +    def setup_logger(self): +        " Add logging infrastructure " +        self.log = logging.getLogger("devtest.{name}".format(name=self.name)) +        self.log_file = os.getenv('_UHD_TEST_LOGFILE', "devtest.log") +        #self.log_level = int(os.getenv('_UHD_TEST_LOG_LEVEL', logging.DEBUG)) +        #self.print_level = int(os.getenv('_UHD_TEST_PRINT_LEVEL', logging.WARNING)) +        self.log_level = logging.DEBUG +        self.print_level = logging.WARNING +        file_handler = logging.FileHandler(self.log_file) +        file_handler.setLevel(self.log_level) +        console_handler = logging.StreamHandler() +        console_handler.setLevel(self.print_level) +        formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') +        file_handler.setFormatter(formatter) +        console_handler.setFormatter(formatter) +        self.log.setLevel(logging.DEBUG) +        self.log.addHandler(file_handler) +        self.log.addHandler(console_handler) +        self.log.info("Starting test with device: {dev}".format(dev=self.args_str)) + +    def tear_down(self): +        pass + +    def tearDown(self): +        self.tear_down() +        if self.results_file: +            open(self.results_file, 'w').write(yaml.dump(self.results, default_flow_style=False)) + +    def report_result(self, testname, key, value): +        """ Store a result as a key/value pair. +        After completion, all results for one test are written to the results file. +        """ +        if not self.results[self.usrp_info['serial']][self.name].has_key(testname): +            self.results[self.usrp_info['serial']][self.name][testname] = {} +        self.results[self.usrp_info['serial']][self.name][testname][key] = value + +    def create_addr_args_str(self, argname="args"): +        """ Returns an args string, usually '--args "type=XXX,serial=YYY" """ +        if len(self.args_str) == 0: +            return '' +        return '--{}={}'.format(argname, self.args_str) + +    def filter_warnings(self, errstr): +        """ Searches errstr for UHD warnings, removes them, and puts them into a separate string. +        Returns (errstr, warnstr), where errstr no longer has warning. """ +        warn_re = re.compile("UHD Warning:\n(?:    .*\n)+") +        warnstr = "\n".join(warn_re.findall(errstr)).strip() +        errstr = warn_re.sub('', errstr).strip() +        return (errstr, warnstr) + +    def filter_stderr(self, stderr, run_results={}): +        """ Filters the output to stderr. run_results[] is a dictionary. +        This function will: +        - Remove UUUUU... strings, since they are generally not a problem. +        - Remove all DDDD and SSSS strings, and add run_results['has_S'] = True +          and run_results['has_D'] = True. +        - Remove warnings and put them in run_results['warnings'] +        - Put the filtered error string into run_results['errors'] and returns the dictionary +        """ +        errstr, run_results['warnings'] = self.filter_warnings(stderr) +        # Scan for underruns and sequence errors / dropped packets  not detected in the counter +        errstr = re.sub('UU+', '', errstr) +        (errstr, n_subs) = re.subn('SS+', '', errstr) +        if n_subs: +            run_results['has_S'] = True +        (errstr, n_subs) = re.subn('DD+', '', errstr) +        if n_subs: +            run_results['has_D'] = True +        errstr = re.sub("\n\n+", "\n", errstr) +        run_results['errors'] = errstr.strip() +        return run_results + +class uhd_example_test_case(uhd_test_case): +    """ +    A test case that runs an example. +    """ + +    def setup_example(self): +        """ +        Override this to add specific setup code. +        """ +        pass + +    def set_up(self): +        """ +        """ +        self.setup_example() + +    def run_test(self, test_name, test_args): +        """ +        Override this to run the actual example. + +        Needs to return either a boolean or a dict with key 'passed' to determine +        pass/fail. +        """ +        raise NotImplementedError + +    def run_example(self, example, args): +        """ +        Run `example' (which has to be a UHD example or utility) with `args'. +        Return results and the app object. +        """ +        self.log.info("Running example: `{example} {args}'".format(example=example, args=" ".join(args))) +        app = shell_application(example) +        app.run(args) +        run_results = { +            'return_code': app.returncode, +            'passed': False, +            'has_D': False, +            'has_S': False, +        } +        run_results = self.filter_stderr(app.stderr, run_results) +        self.log.info('STDERR Output:') +        self.log.info(str(app.stderr)) +        return (app, run_results) + + +    def report_example_results(self, test_name, run_results): +        for key in sorted(run_results): +            self.log.info('{key} = {val}'.format(key=key, val=run_results[key])) +            self.report_result( +                test_name, +                key, run_results[key] +            ) +        if run_results.has_key('passed'): +            self.report_result( +                test_name, +                'status', +                'Passed' if run_results['passed'] else 'Failed', +            ) +        if run_results.has_key('errors'): +            self.report_result( +                test_name, +                'errors', +                'Yes' if run_results['errors'] else 'No', +            ) + +    def test_all(self): +        """ +        Hook for test runner. Needs to be a class method that starts with 'test'. +        Calls run_test(). +        """ +        for test_name, test_args in self.test_params.iteritems(): +            if not test_args.has_key('product') or (self.usrp_info['product'] in test_args.get('products', [])): +                run_results = self.run_test(test_name, test_args) +                passed = bool(run_results) +                if isinstance(run_results, dict): +                    passed = run_results['passed'] +                self.assertTrue( +                    passed, +                    msg="Errors occurred during test `{t}'. Check log file for details.\nRun results:\n{r}".format( +                        t=test_name, r=yaml.dump(run_results, default_flow_style=False) +                    ) +                ) + diff --git a/host/tests/devtest/usrp_probe.py b/host/tests/devtest/usrp_probe.py new file mode 100644 index 000000000..ba3c645e4 --- /dev/null +++ b/host/tests/devtest/usrp_probe.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +# +# 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/>. +# +""" Run uhd_find_devices and parse the output. """ + +import re +import subprocess + +def get_usrp_list(device_filter=None): +    """ Returns a list of dicts that contain USRP info """ +    try: +        if device_filter is not None: +            output = subprocess.check_output(['uhd_find_devices', '--args', device_filter]) +        else: +            output = subprocess.check_output('uhd_find_devices') +    except subprocess.CalledProcessError: +        return [] +    split_re = "\n*-+\n-- .*\n-+\n" +    uhd_strings = re.split(split_re, output) +    result = [] +    for uhd_string in uhd_strings: +        if not re.match("Device Address", uhd_string): +            continue +        this_result = {k: v for k, v in re.findall("    ([a-z]+): (.*)", uhd_string)} +        args_string = "" +        try: +            args_string = "type={},serial={}".format(this_result['type'], this_result['serial']) +        except KeyError: +            continue +        this_result['args'] = args_string +        result.append(this_result) +    return result + +if __name__ == "__main__": +    print get_usrp_list() +    print get_usrp_list('type=x300') diff --git a/host/tests/devtest/usrp_probe_test.py b/host/tests/devtest/usrp_probe_test.py new file mode 100755 index 000000000..a136a2af7 --- /dev/null +++ b/host/tests/devtest/usrp_probe_test.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +# +# 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/>. +# +""" Run the test for tx_burst """ + +import re +from uhd_test_base import uhd_example_test_case + +class uhd_usrp_probe_test(uhd_example_test_case): +    """ Run uhd_usrp_probe """ +    tests = { +        'default': { +            'init-only': False, +        }, +    } + +    def setup_example(self): +        """ +        Set args. +        """ +        self.test_params = uhd_usrp_probe_test.tests + +    def run_test(self, test_name, test_args): +        """ Run the app and scrape for the failure messages. """ +        self.log.info('Running test {name}'.format(name=test_name)) +        # Run example: +        args = [ +            self.create_addr_args_str(), +        ] +        if test_args.get('init-only'): +            args.append('--init-only') +        (app, run_results) = self.run_example('uhd_usrp_probe', args) +        # Evaluate pass/fail: +        run_results['passed'] = all([ +            app.returncode == 0, +        ]) +        self.report_example_results(test_name, run_results) +        return run_results + diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt index 4f56dad0d..7e23b18c3 100644 --- a/host/utils/CMakeLists.txt +++ b/host/utils/CMakeLists.txt @@ -48,18 +48,24 @@ FOREACH(util_source ${util_runtime_sources})      UHD_INSTALL(TARGETS ${util_name} RUNTIME DESTINATION ${RUNTIME_DIR} COMPONENT utilities)  ENDFOREACH(util_source) -ADD_EXECUTABLE(usrp_x3xx_fpga_burner ${x3xx_burner_sources}) -TARGET_LINK_LIBRARIES(usrp_x3xx_fpga_burner uhd ${Boost_LIBRARIES}) -UHD_INSTALL(TARGETS usrp_x3xx_fpga_burner RUNTIME DESTINATION ${RUNTIME_DIR} COMPONENT utilities) +IF(ENABLE_X300) +    ADD_EXECUTABLE(usrp_x3xx_fpga_burner ${x3xx_burner_sources}) +    TARGET_LINK_LIBRARIES(usrp_x3xx_fpga_burner uhd ${Boost_LIBRARIES}) +    UHD_INSTALL(TARGETS usrp_x3xx_fpga_burner RUNTIME DESTINATION ${RUNTIME_DIR} COMPONENT utilities) +ENDIF(ENABLE_X300)  ########################################################################  # Utilities that get installed into the share path  ########################################################################  SET(util_share_sources +    converter_benchmark.cpp      query_gpsdo_sensors.cpp      usrp_burn_db_eeprom.cpp      usrp_burn_mb_eeprom.cpp  ) +SET(util_share_sources_py +    converter_benchmark.py +)  IF(ENABLE_USB)      LIST(APPEND util_share_sources          fx2_init_eeprom.cpp @@ -109,9 +115,20 @@ FOREACH(util_source ${util_share_sources})      TARGET_LINK_LIBRARIES(${util_name} uhd ${Boost_LIBRARIES})      UHD_INSTALL(TARGETS ${util_name} RUNTIME DESTINATION ${PKG_LIB_DIR}/utils COMPONENT utilities)  ENDFOREACH(util_source) +FOREACH(util_source ${util_share_sources_py}) +    UHD_INSTALL(PROGRAMS +        ${CMAKE_CURRENT_SOURCE_DIR}/${util_source} +        DESTINATION ${PKG_LIB_DIR}/utils +        COMPONENT utilities +    ) +ENDFOREACH(util_source) -UHD_INSTALL(TARGETS usrp_n2xx_simple_net_burner RUNTIME DESTINATION ${PKG_LIB_DIR}/utils COMPONENT utilities) -UHD_INSTALL(TARGETS usrp_x3xx_fpga_burner RUNTIME DESTINATION ${PKG_LIB_DIR}/utils COMPONENT utilities) +IF(ENABLE_USRP2) +    UHD_INSTALL(TARGETS usrp_n2xx_simple_net_burner RUNTIME DESTINATION ${PKG_LIB_DIR}/utils COMPONENT utilities) +ENDIF(ENABLE_USRP2) +IF(ENABLE_X300) +    UHD_INSTALL(TARGETS usrp_x3xx_fpga_burner RUNTIME DESTINATION ${PKG_LIB_DIR}/utils COMPONENT utilities) +ENDIF(ENABLE_X300)  #UHD images downloader configuration  CONFIGURE_FILE( diff --git a/host/utils/converter_benchmark.cpp b/host/utils/converter_benchmark.cpp new file mode 100644 index 000000000..0f38e8518 --- /dev/null +++ b/host/utils/converter_benchmark.cpp @@ -0,0 +1,433 @@ +// +// 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/>. +// + +#include <uhd/utils/safe_main.hpp> +#include <uhd/types/dict.hpp> +#include <uhd/convert.hpp> +#include <uhd/exception.hpp> +#include <boost/program_options.hpp> +#include <boost/format.hpp> +#include <boost/timer.hpp> +#include <boost/algorithm/string.hpp> +#include <iostream> +#include <iomanip> +#include <map> +#include <complex> + +namespace po = boost::program_options; +using namespace uhd::convert; + +enum buf_init_t { +    RANDOM, INC +}; + +// Convert `sc16_item32_le' -> `sc16' +// Finds the first _ in format and returns the string +// until then. Returns the entire string if no _ is found. +std::string format_to_type(const std::string &format) +{ +    std::string ret_val = ""; +    for (size_t i = 0; i < format.length(); i++) { +        if (format[i] == '_') { +            return ret_val; +        } +        ret_val.append(1, format[i]); +    } + +    return ret_val; +} + +void configure_conv( +        converter::sptr conv, +        const std::string &in_type, +        const std::string &out_type +) { +    if (in_type == "sc16") { +        if (out_type == "fc32") { +            std::cout << "Setting scalar to 32767." << std::endl; +            conv->set_scalar(32767.); +            return; +        } +    } + +    if (in_type == "fc32") { +        if (out_type == "sc16") { +            std::cout << "Setting scalar to 32767." << std::endl; +            conv->set_scalar(32767.); +            return; +        } +    } + +    std::cout << "No configuration required." << std::endl; +} + +template <typename T> +void init_random_vector_complex_float(std::vector<char> &buf_ptr, const size_t n_items) +{ +    std::complex<T> * const buf = reinterpret_cast<std::complex<T> * const>(&buf_ptr[0]); +    for (size_t i = 0; i < n_items; i++) { +        buf[i] = std::complex<T>( +            T((std::rand()/double(RAND_MAX/2)) - 1), +            T((std::rand()/double(RAND_MAX/2)) - 1) +        ); +    } +} + +template <typename T> +void init_random_vector_complex_int(std::vector<char> &buf_ptr, const size_t n_items) +{ +    std::complex<T> * const buf = reinterpret_cast<std::complex<T> * const>(&buf_ptr[0]); +    for (size_t i = 0; i < n_items; i++) { +        buf[i] = std::complex<T>(T(std::rand()), T(std::rand())); +    } +} + +template <typename T> +void init_random_vector_real_int(std::vector<char> &buf_ptr, size_t n_items) +{ +    T * const buf = reinterpret_cast<T * const>(&buf_ptr[0]); +    for (size_t i = 0; i < n_items; i++) { +        buf[i] = T(std::rand()); +    } +} + +// Fill a buffer with increasing numbers +template <typename T> +void init_inc_vector(std::vector<char> &buf_ptr, size_t n_items) +{ +    T * const buf = reinterpret_cast<T * const>(&buf_ptr[0]); +    for (size_t i = 0; i < n_items; i++) { +        buf[i] = T(i); +    } +} + +void init_buffers( +        std::vector< std::vector<char> > &buf, +        const std::string &type, +        size_t bytes_per_item, +        buf_init_t buf_seed_mode +) { +    if (buf.empty()) { +        return; +    } +    size_t n_items = buf[0].size() / bytes_per_item; + +    /// Fill with incrementing integers +    if (buf_seed_mode == INC) { +        for (size_t i = 0; i < buf.size(); i++) { +            if (type == "sc8") { +                init_inc_vector< std::complex<boost::int8_t> >(buf[i], n_items); +            } else if (type == "sc16") { +                init_inc_vector< std::complex<boost::int16_t> >(buf[i], n_items); +            } else if (type == "sc32") { +                init_inc_vector< std::complex<boost::int32_t> >(buf[i], n_items); +            } else if (type == "fc32") { +                init_inc_vector< std::complex<float> >(buf[i], n_items); +            } else if (type == "fc64") { +                init_inc_vector< std::complex<double> >(buf[i], n_items); +            } else if (type == "s8") { +                init_inc_vector< boost::int8_t >(buf[i], n_items); +            } else if (type == "s16") { +                init_inc_vector< boost::int16_t >(buf[i], n_items); +            } else if (type == "item32") { +                init_inc_vector< boost::uint32_t >(buf[i], n_items); +                init_random_vector_real_int<boost::uint32_t>(buf[i], n_items); +            } else { +                throw uhd::runtime_error(str( +                            boost::format("Cannot handle data type: %s") % type +                )); +            } +        } + +        return; +    } + +    assert(buf_seed_mode == RANDOM); + +    /// Fill with random data +    for (size_t i = 0; i < buf.size(); i++) { +        if (type == "sc8") { +            init_random_vector_complex_int<boost::int8_t>(buf[i], n_items); +        } else if (type == "sc16") { +            init_random_vector_complex_int<boost::int16_t>(buf[i], n_items); +        } else if (type == "sc32") { +            init_random_vector_complex_int<boost::int32_t>(buf[i], n_items); +        } else if (type == "fc32") { +            init_random_vector_complex_float<float>(buf[i], n_items); +        } else if (type == "fc64") { +            init_random_vector_complex_float<double>(buf[i], n_items); +        } else if (type == "s8") { +            init_random_vector_real_int<boost::int8_t>(buf[i], n_items); +        } else if (type == "s16") { +            init_random_vector_real_int<boost::int16_t>(buf[i], n_items); +        } else if (type == "item32") { +            init_random_vector_real_int<boost::uint32_t>(buf[i], n_items); +        } else { +            throw uhd::runtime_error(str( +                boost::format("Cannot handle data type: %s") % type +            )); +        } +    } +} + +// Returns time elapsed +double run_benchmark( +        converter::sptr conv, +        const std::vector<const void *> &input_buf_refs, +        const std::vector<void *> &output_buf_refs, +        size_t n_items, +        size_t iterations +) { +    boost::timer benchmark_timer; +    for (size_t i = 0; i < iterations; i++) { +        conv->conv(input_buf_refs, output_buf_refs, n_items); +    } +    return benchmark_timer.elapsed(); +} + +template <typename T> +std::string void_ptr_to_hexstring(const void *v_ptr, size_t index) +{ +    const T *ptr = reinterpret_cast<const T *>(v_ptr); +    return str(boost::format("%X") % ptr[index]); +} + +std::string item_to_hexstring( +    const void *v_ptr, +    size_t index, +    const std::string &type +) { +    if (type == "fc32") { +        return void_ptr_to_hexstring<uint64_t>(v_ptr, index); +    } +    else if (type == "sc16" || type == "item32") { +        return void_ptr_to_hexstring<uint32_t>(v_ptr, index); +    } +    else if (type == "sc8" || type == "s16") { +        return void_ptr_to_hexstring<uint16_t>(v_ptr, index); +    } +    else if (type == "u8") { +        return void_ptr_to_hexstring<uint8_t>(v_ptr, index); +    } +    else { +        return str(boost::format("<unhandled data type: %s>") % type); +    } +} + +std::string item_to_string( +    const void *v_ptr, +    size_t index, +    const std::string &type, +    const bool print_hex +) { +    if (print_hex) { +        return item_to_hexstring(v_ptr, index, type); +    } + +    if (type == "sc16") { +        const std::complex<boost::int16_t> *ptr = reinterpret_cast<const std::complex<boost::int16_t> *>(v_ptr); +        return boost::lexical_cast<std::string>(ptr[index]); +    } +    else if (type == "sc8") { +        const std::complex<boost::int8_t> *ptr = reinterpret_cast<const std::complex<boost::int8_t> *>(v_ptr); +        return boost::lexical_cast<std::string>(ptr[index]); +    } +    else if (type == "fc32") { +        const std::complex<float> *ptr = reinterpret_cast<const std::complex<float> *>(v_ptr); +        return boost::lexical_cast<std::string>(ptr[index]); +    } +    else if (type == "item32") { +        const boost::uint32_t *ptr = reinterpret_cast<const boost::uint32_t *>(v_ptr); +        return boost::lexical_cast<std::string>(ptr[index]); +    } +    else if (type == "s16") { +        const boost::int16_t *ptr = reinterpret_cast<const boost::int16_t *>(v_ptr); +        return boost::lexical_cast<std::string>(ptr[index]); +    } +    else { +        return str(boost::format("<unhandled data type: %s>") % type); +    } +} + +int UHD_SAFE_MAIN(int argc, char *argv[]) +{ +    std::string in_format, out_format; +    std::string priorities; +    std::string seed_mode; +    priority_type prio = -1, max_prio; +    size_t iterations, n_samples; +    size_t n_inputs, n_outputs; +    buf_init_t buf_seed_mode = RANDOM; + +    /// Command line arguments +    po::options_description desc("Converter benchmark options:"); +    desc.add_options() +        ("help", "help message") +        ("in",  po::value<std::string>(&in_format), "Input format (e.g. 'sc16')") +        ("out", po::value<std::string>(&out_format), "Output format (e.g. 'sc16')") +        ("samples",  po::value<size_t>(&n_samples)->default_value(1000000), "Number of samples per iteration") +        ("iterations",  po::value<size_t>(&iterations)->default_value(10000), "Number of iterations per benchmark") +        ("priorities", po::value<std::string>(&priorities)->default_value("default"), "Converter priorities. Can be 'default', 'all', or a comma-separated list of priorities.") +        ("max-prio", po::value<priority_type>(&max_prio)->default_value(4), "Largest available priority (advanced feature)") +        ("n-inputs",   po::value<size_t>(&n_inputs)->default_value(1),  "Number of input vectors") +        ("n-outputs",  po::value<size_t>(&n_outputs)->default_value(1), "Number of output vectors") +        ("debug-converter", "Skip benchmark and print conversion results. Implies iterations==1 and will only run on a single converter.") +        ("seed-mode", po::value<std::string>(&seed_mode)->default_value("random"), "How to initialize the data: random, incremental") +        ("hex", "When using debug mode, dump memory in hex") +    ; +    po::variables_map vm; +    po::store(po::parse_command_line(argc, argv, desc), vm); +    po::notify(vm); + +    //print the help message +    if (vm.count("help")){ +        std::cout << boost::format("UHD Converter Benchmark Tool %s") % desc << std::endl << std::endl; +        std::cout << "  Use this to benchmark or debug converters." << std::endl +                  << "  When using as a benchmark tool, it will output the execution time\n" +                     "  for every conversion run in CSV format to stdout. Every line between\n" +                     "  the output delimiters {{{ }}} is of the format: <PRIO>,<TIME IN MILLISECONDS>\n" +                     "  When using for converter debugging, every line is formatted as\n" +                     "  <INPUT_VALUE>,<OUTPUT_VALUE>\n" << std::endl; +        return EXIT_FAILURE; +    } + +    // Parse more arguments +    if (seed_mode == "incremental") { +        buf_seed_mode = INC; +    } else if (seed_mode == "random") { +        buf_seed_mode = RANDOM; +    } else { +        std::cout << "Invalid argument: --seed-mode must be either 'incremental' or 'random'." << std::endl; +    } + +    bool debug_mode = bool(vm.count("debug-converter")); +    if (debug_mode) { +        iterations = 1; +    } + +    /// Create the converter(s) ////////////////////////////////////////////// +    id_type converter_id; +    converter_id.input_format  = in_format; +    converter_id.output_format = out_format; +    converter_id.num_inputs    = n_inputs; +    converter_id.num_outputs   = n_outputs; +    std::cout << "Requested converter format: " << converter_id.to_string() +              << std::endl; +    uhd::dict<priority_type, converter::sptr> conv_list; +    if (priorities == "default" or priorities.empty()) { +        try { +            conv_list[prio] = get_converter(converter_id, prio)(); // Can throw a uhd::key_error +        } catch(const uhd::key_error &e) { +            std::cout << "No converters found." << std::endl; +            return EXIT_FAILURE; +        } +    } else if (priorities == "all") { +        for (priority_type i = 0; i < max_prio; i++) { +            try { +                // get_converter() returns a factory function, execute that immediately: +                converter::sptr conv_for_prio = get_converter(converter_id, i)(); // Can throw a uhd::key_error +                conv_list[i] = conv_for_prio; +            } catch (...) { +                continue; +            } +        } +    } else { // Assume that priorities contains a list of prios (e.g. 0,2,3) +        std::vector<std::string> prios_in_list; +        boost::split( +                prios_in_list, +                priorities, +                boost::is_any_of(","), // Split at , +                boost::token_compress_on // Avoid empty results +        ); +        BOOST_FOREACH(const std::string &this_prio, prios_in_list) { +            size_t prio_index = boost::lexical_cast<size_t>(this_prio); +            converter::sptr conv_for_prio = get_converter(converter_id, prio_index)(); // Can throw a uhd::key_error +            conv_list[prio_index] = conv_for_prio; +        } +    } +    std::cout << "Found " << conv_list.size() << " converter(s)." << std::endl; + +    /// Create input and output buffers /////////////////////////////////////// +    // First, convert the types to plain types (e.g. sc16_item32_le -> sc16) +    const std::string in_type  = format_to_type(in_format); +    const std::string out_type = format_to_type(out_format); +    const size_t in_size  = get_bytes_per_item(in_type); +    const size_t out_size = get_bytes_per_item(out_type); +    // Create the buffers and fill them with random data & zeros, respectively +    std::vector< std::vector<char> > input_buffers(n_inputs, std::vector<char>(in_size * n_samples, 0)); +    std::vector< std::vector<char> > output_buffers(n_outputs, std::vector<char>(out_size * n_samples, 0)); +    init_buffers(input_buffers, in_type, in_size, buf_seed_mode); +    // Create ref vectors for the converter: +    std::vector<const void *>  input_buf_refs(n_inputs); +    std::vector<void *> output_buf_refs(n_outputs); +    for (size_t i = 0; i < n_inputs; i++) { +        input_buf_refs[i] = reinterpret_cast<const void *>(&input_buffers[i][0]); +    } +    for (size_t i = 0; i < n_outputs; i++) { +        output_buf_refs[i] = reinterpret_cast<void *>(&output_buffers[i][0]); +    } + +    /// Final configurations to the converter: +    std::cout << "Configuring converters:" << std::endl; +    BOOST_FOREACH(priority_type prio_i, conv_list.keys()) { +        std::cout << "* [" << prio_i << "]: "; +        configure_conv(conv_list[prio_i], in_type, out_type); +    } + +    /// Run the benchmark for every converter //////////////////////////////// +    std::cout << "{{{" << std::endl; +    if (not debug_mode) { +        std::cout << "prio,duration_ms,avg_duration_ms,n_samples,iterations" << std::endl; +        BOOST_FOREACH(priority_type prio_i, conv_list.keys()) { +            double duration = run_benchmark( +                    conv_list[prio_i], +                    input_buf_refs, +                    output_buf_refs, +                    n_samples, +                    iterations +            ); +            std::cout << boost::format("%i,%d,%d,%d,%d") +                % prio_i +                % (duration * 1000) +                % (duration * 1000.0 / iterations) +                % n_samples +                % iterations +                << std::endl; +        } +    } + +    /// Or run debug mode, which runs one conversion and prints the results //// +    if (debug_mode) { +        // Only run on the first converter: +        run_benchmark( +            conv_list[conv_list.keys().at(0)], +            input_buf_refs, +            output_buf_refs, +            n_samples, +            iterations +        ); +        for (size_t i = 0; i < n_samples; i++) { +            std::cout << item_to_string(input_buf_refs[0], i, in_type, vm.count("hex")) +                      << ";" +                      << item_to_string(reinterpret_cast< const void * >(output_buf_refs[0]), i, out_type, vm.count("hex")) +                      << std::endl; +        } +    } +    std::cout << "}}}" << std::endl; + +    return EXIT_SUCCESS; +} diff --git a/host/utils/converter_benchmark.py b/host/utils/converter_benchmark.py new file mode 100644 index 000000000..c3cab8753 --- /dev/null +++ b/host/utils/converter_benchmark.py @@ -0,0 +1,193 @@ +#!/usr/bin/env python +# +# 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/>. +# +""" +Wrap the converter_benchmark tool and produce prettier results. +""" + +from __future__ import print_function +import argparse +import csv +import subprocess + +INTRO_SETUP = { +    'n_samples': { +        'title': 'Samples per iteration', +    }, +    'iterations': { +        'title': 'Number of iterations' +    }, +} + +TABLE_SETUP = { +    'prio': { +        'title': 'Priority', +    }, +    'duration_ms': { +        'title': 'Total Duration (ms)', +    }, +    'avg_duration_ms': { +        'title': 'Avg. Duration (ms)', +    }, +} + +def run_benchmark(args): +    """ Run the tool with the given arguments, return the section in the {{{ }}} brackets """ +    call_args = ['./converter_benchmark',] +    for k, v in args.__dict__.iteritems(): +        k = k.replace('_', '-') +        if v is None: +            continue +        if k in ('debug-converter', 'hex'): +            if v: +                call_args.append('--{0}'.format(k)) +            continue +        call_args.append('--{0}'.format(k)) +        call_args.append(str(v)) +    print(call_args) +    try: +        output = subprocess.check_output(call_args) +    except subprocess.CalledProcessError as ex: +        print(ex.output) +        exit(ex.returncode) +    header_out, csv_output = output.split('{{{', 1) +    csv_output = csv_output.split('}}}', 1) +    assert len(csv_output) == 2 and csv_output[1].strip() == '' +    return header_out, csv_output[0] + +def print_stats_table(args, csv_output): +    """ +    Print stats. +    """ +    reader = csv.reader(csv_output.strip().split('\n'), delimiter=',') +    title_row = reader.next() +    row_widths = [0,] * len(TABLE_SETUP) +    for idx, row in enumerate(reader): +        if idx == 0: +            # Print intro: +            for k, v in INTRO_SETUP.iteritems(): +                print("{title}: {value}".format( +                    title=v['title'], +                    value=row[title_row.index(k)], +                )) +            print("") +            # Print table header +            for idx, item in enumerate(TABLE_SETUP): +                print(" {title} ".format(title=TABLE_SETUP[item]['title']), end='') +                row_widths[idx] = len(TABLE_SETUP[item]['title']) +                if idx < len(TABLE_SETUP) - 1: +                    print("|", end='') +            print("") +            for idx, item in enumerate(TABLE_SETUP): +                print("-" * (row_widths[idx] + 2), end='') +                if idx < len(TABLE_SETUP) - 1: +                    print("+", end='') +            print("") +        # Print actual row data +        for idx, item in enumerate(TABLE_SETUP): +            format_str = " {{item:>{n}}} ".format(n=row_widths[idx]) +            print(format_str.format(item=row[title_row.index(item)]), end='') +            if idx < len(TABLE_SETUP) - 1: +                print("|", end='') +        print("") + +def print_debug_table(args, csv_output): +    """ +    Print debug output. +    """ +    reader = csv.reader(csv_output.strip().split('\n'), delimiter=';') +    print_widths_hex = { +        'u8': 2, +        'sc16': 8, +        'fc32': 16, +        's16': 4, +    } +    if args.hex: +        format_str = "{{0[0]:0>{n_in}}} => {{0[1]:0>{n_out}}}".format( +            n_in=print_widths_hex[getattr(args, 'in').split('_', 1)[0]], +            n_out=print_widths_hex[args.out.split('_', 1)[0]] +        ) +    else: +        format_str = "{0[0]}\t=>\t{0[1]}" +    for row in reader: +        print(format_str.format(row)) + +def setup_argparse(): +    """ Configure arg parser. """ +    parser = argparse.ArgumentParser( +        description="UHD Converter Benchmark + Debugging Utility.", +    ) +    parser.add_argument( +        "-i", "--in", required=True, +        help="Input format  (e.g. 'sc16')" +    ) +    parser.add_argument( +        "-o", "--out", required=True, +        help="Output format  (e.g. 'sc16')" +    ) +    parser.add_argument( +        "-s", "--samples", type=int, +        help="Number of samples per iteration" +    ) +    parser.add_argument( +        "-N", "--iterations", type=int, +        help="Number of iterations per benchmark", +    ) +    parser.add_argument( +        "-p", "--priorities", +        help="Converter priorities. Can be 'default', 'all', or a comma-separated list of priorities.", +    ) +    parser.add_argument( +        "--max-prio", type=int, +        help="Largest available priority (advanced feature)", +    ) +    parser.add_argument( +        "--n-inputs", type=int, +        help="Number of input vectors", +    ) +    parser.add_argument( +        "--n-outputs", type=int, +        help="Number of output vectors", +    ) +    parser.add_argument( +        "--seed-mode", choices=('random', 'incremental'), +        help="How to initialize the data: random, incremental", +    ) +    parser.add_argument( +        "--debug-converter", action='store_true', +        help="Skip benchmark and print conversion results. Implies iterations==1 and will only run on a single converter.", +    ) +    parser.add_argument( +        "--hex", action='store_true', +        help="In debug mode, display data as hex values.", +    ) +    return parser + +def main(): +    """ Go, go, go! """ +    args = setup_argparse().parse_args() +    print("Running converter benchmark...") +    header_out, csv_output = run_benchmark(args) +    print(header_out) +    if args.debug_converter: +        print_debug_table(args, csv_output) +    else: +        print_stats_table(args, csv_output) + +if __name__ == "__main__": +    main() + diff --git a/host/utils/query_gpsdo_sensors.cpp b/host/utils/query_gpsdo_sensors.cpp index 3b98a634c..4c17c6044 100644 --- a/host/utils/query_gpsdo_sensors.cpp +++ b/host/utils/query_gpsdo_sensors.cpp @@ -1,5 +1,5 @@  // -// Copyright 2012,2014 Ettus Research LLC +// Copyright 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 @@ -38,7 +38,6 @@ void print_notes(void) {    std::cout << boost::format("**************************************Helpful Notes on Clock/PPS Selection**************************************\n");    std::cout << boost::format("As you can see, the default 10 MHz Reference and 1 PPS signals are now from the GPSDO.\n");    std::cout << boost::format("If you would like to use the internal reference(TCXO) in other applications, you must configure that explicitly.\n"); -  std::cout << boost::format("You can no longer select the external SMAs for 10 MHz or 1 PPS signaling.\n");    std::cout << boost::format("****************************************************************************************************************\n");  } @@ -51,7 +50,7 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){    po::options_description desc("Allowed options");    desc.add_options()      ("help", "help message") -    ("args", po::value<std::string>(&args)->default_value(""), "Specify a single USRP.") +    ("args", po::value<std::string>(&args)->default_value(""), "Device address arguments specifying a single USRP")      ;    po::variables_map vm;    po::store(po::parse_command_line(argc, argv, desc), vm); @@ -59,8 +58,11 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){    //Print the help message    if (vm.count("help")) { -    std::cout << boost::format("Query GPSDO Sensors %s") % desc << std::endl; -    return EXIT_FAILURE; +      std::cout << boost::format("Query GPSDO Sensors, try to lock the reference oscillator to the GPS disciplined clock, and set the device time to GPS time") +          << std::endl +          << std::endl +          << desc; +      return EXIT_FAILURE;    }    //Create a USRP device @@ -68,9 +70,6 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){    uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);    std::cout << boost::format("Using Device: %s\n") % usrp->get_pp_string(); -  print_notes(); - -    //Verify GPS sensors are present (i.e. EEPROM has been burnt)    std::vector<std::string> sensor_names = usrp->get_mboard_sensor_names(0); @@ -82,38 +81,96 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){      exit(EXIT_FAILURE);    } +  // Explicitly set time source to gpsdo +  boost::this_thread::sleep(boost::posix_time::seconds(1)); +  try { +      usrp->set_time_source("gpsdo"); +  } catch (uhd::value_error &e) { +      std::cout << "could not set the time source to \"gpsdo\"; error was:" <<std::endl; +      std::cout << e.what() << std::endl; +      std::cout << "trying \"external\"..." <<std::endl; +      try { +          usrp->set_time_source("external"); +      } catch (uhd::value_error &e) { +          std::cout << "\"external\" failed, too." << std::endl; +      } +  } +  std::cout<< std::endl << "Time source is now " << usrp->get_time_source(0) << std::endl; +    //Check for GPS lock    uhd::sensor_value_t gps_locked = usrp->get_mboard_sensor("gps_locked",0);    if(not gps_locked.to_bool()) { -    std::cout << boost::format("\nGPS does not have lock. Wait a few minutes and try again.\n"); -    std::cout << boost::format("NMEA strings and device time may not be accurate until lock is achieved.\n\n"); -  } else -      std::cout << boost::format("GPS Locked\n"); +      std::cout << boost::format("\nGPS does not have lock. Wait a few minutes and try again.\n"); +      std::cout << boost::format("NMEA strings and device time may not be accurate until lock is achieved.\n\n"); +  } else { +      std::cout << boost::format("GPS Locked"); +  } + +  std::cout << "\nSetting the reference clock source to \"gpsdo\"...\n"; +  try { +      usrp->set_clock_source("gpsdo"); +  } catch (uhd::value_error &e) { +      std::cout << "could not set the clock source to \"gpsdo\"; error was:" <<std::endl; +      std::cout << e.what() << std::endl; +      std::cout << "trying \"external\"..." <<std::endl; +      try{ +          usrp->set_clock_source("external"); +      } catch (uhd::value_error &e) { +          std::cout << "\"external\" failed, too." << std::endl; +      } +  } +  std::cout<< std::endl << "Clock source is now " << usrp->get_clock_source(0) << std::endl; + +  print_notes(); +    //Check for 10 MHz lock    if(std::find(sensor_names.begin(), sensor_names.end(), "ref_locked") != sensor_names.end()) { -    uhd::sensor_value_t gps_locked = usrp->get_mboard_sensor("ref_locked",0); -    if(not gps_locked.to_bool()) { -      std::cout << boost::format("USRP NOT Locked to GPSDO 10 MHz Reference.\n"); -      std::cout << boost::format("Double check installation instructions (N2X0/E1X0 only): https://www.ettus.com/content/files/gpsdo-kit_4.pdf\n\n"); -    } else -        std::cout << boost::format("USRP Locked to GPSDO 10 MHz Reference.\n"); -  }else -    std::cout << boost::format("ref_locked sensor not present on this board.\n"); - -  // Explicitly set time source to gpsdo -  usrp->set_time_source("gpsdo"); +      uhd::sensor_value_t gps_locked = usrp->get_mboard_sensor("ref_locked",0); +      if(not gps_locked.to_bool()) { +          std::cout << boost::format("USRP NOT Locked to GPSDO 10 MHz Reference.\n"); +          std::cout << boost::format("Double check installation instructions (N2X0/E1X0 only): https://www.ettus.com/content/files/gpsdo-kit_4.pdf\n\n"); +          std::cout << boost::format("Locking the internal reference to the GPSDO might take a second to reach stability. Retrying in 10 s...\n\n"); +          boost::this_thread::sleep(boost::posix_time::seconds(10)); +      } +      if(usrp->get_mboard_sensor("ref_locked",0).to_bool()) { +          std::cout << boost::format("USRP Locked to GPSDO 10 MHz Reference.\n"); +      } +  } else { +      std::cout << boost::format("ref_locked sensor not present on this board.\n"); +  }    //Check PPS and compare UHD device time to GPS time    boost::this_thread::sleep(boost::posix_time::seconds(1));    uhd::sensor_value_t gps_time = usrp->get_mboard_sensor("gps_time"); -  const time_t pc_clock_time = time(NULL); -  const uhd::time_spec_t last_pps_time = usrp->get_time_last_pps(); +  uhd::time_spec_t last_pps_time = usrp->get_time_last_pps(); + +  //we only care about the full seconds +  signed gps_seconds = gps_time.to_int(); +  long long pps_seconds = last_pps_time.to_ticks(1.0); + +  if(pps_seconds != gps_seconds) { +      std::cout << boost::format("\nGPS and UHD Device time are NOT aligned;\nlast_pps: %ld vs gps: %ld. Trying to set the device time to GPS time...") +                % pps_seconds % gps_seconds +                << std::endl; +      //full next after next second +      uhd::time_spec_t next_pps_time(gps_seconds + 2.0); +      //instruct the USRP to wait for the next PPS edge, then set the new time on the following PPS +      usrp->set_time_unknown_pps(next_pps_time); +      //allow some time to make sure the PPS has come… +      boost::this_thread::sleep(boost::posix_time::seconds(1.1)); +      //…then ask +      gps_seconds = usrp->get_mboard_sensor("gps_time").to_int(); +      pps_seconds = usrp->get_time_last_pps().to_ticks(1.0); +  } -  if (last_pps_time.to_ticks(1.0) == gps_time.to_int()) { +  std::cout << boost::format("last_pps: %ld vs gps: %ld.") +            % pps_seconds % gps_seconds +            << std::endl; +  if (pps_seconds == gps_seconds) {        std::cout << boost::format("GPS and UHD Device time are aligned.\n");    } else { -      std::cout << boost::format("\nGPS and UHD Device time are NOT aligned last_pps: %ld vs gps: %ld. Try re-running the program. Double check 1 PPS connection from GPSDO.\n\n") % last_pps_time.to_ticks(1.0) % gps_time.to_int() << std::endl; +      std::cout << boost::format("Could not align UHD Device time to GPS time. Giving up.\n");    }    //print NMEA strings @@ -121,12 +178,14 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){        uhd::sensor_value_t gga_string = usrp->get_mboard_sensor("gps_gpgga");        uhd::sensor_value_t rmc_string = usrp->get_mboard_sensor("gps_gprmc");        std::cout << boost::format("Printing available NMEA strings:\n"); -      std::cout << boost::format("%s\n%s\n%s\n") % gga_string.to_pp_string() % rmc_string.to_pp_string() % gps_time.to_pp_string(); -  } catch (std::exception &) { +      std::cout << boost::format("%s\n%s\n") % gga_string.to_pp_string() % rmc_string.to_pp_string(); +  } catch (uhd::lookup_error &e) {        std::cout << "NMEA strings not implemented for this device." << std::endl;    } -  std::cout << boost::format("UHD Device time: %.0f seconds\n") % (last_pps_time.get_real_secs()); -  std::cout << boost::format("PC Clock time: %.0f seconds\n") % pc_clock_time; +  std::cout << boost::format("GPS Epoch time at last PPS: %.5f seconds\n") % usrp->get_mboard_sensor("gps_time").to_real(); +  std::cout << boost::format("UHD Device time last PPS:   %.5f seconds\n") % (usrp->get_time_last_pps().get_real_secs()); +  std::cout << boost::format("UHD Device time right now:  %.5f seconds\n") % (usrp->get_time_now().get_real_secs()); +  std::cout << boost::format("PC Clock time:              %.5f seconds\n") % time(NULL);    //finished    std::cout << boost::format("\nDone!\n\n"); | 
