aboutsummaryrefslogtreecommitdiffstats
path: root/host
diff options
context:
space:
mode:
Diffstat (limited to 'host')
-rw-r--r--host/cmake/Modules/UHDVersion.cmake6
-rw-r--r--host/cmake/msvc/inttypes.h301
-rw-r--r--host/cmake/msvc/stdint.h226
-rw-r--r--host/include/uhd/types/CMakeLists.txt1
-rw-r--r--host/include/uhd/types/stdint.hpp53
-rw-r--r--host/include/uhd/version.hpp.in4
-rw-r--r--host/lib/convert/convert_item32.cpp3
-rw-r--r--host/lib/convert/gen_convert_general.py128
-rw-r--r--host/lib/transport/super_recv_packet_handler.hpp6
-rw-r--r--host/lib/usrp/b200/b200_impl.cpp16
-rw-r--r--host/lib/usrp/multi_usrp.cpp4
-rw-r--r--host/lib/utils/msg.cpp2
-rw-r--r--host/tests/CMakeLists.txt2
-rw-r--r--host/tests/convert_test.cpp163
-rw-r--r--host/tests/devtest/CMakeLists.txt40
-rw-r--r--host/tests/devtest/README.md28
-rwxr-xr-xhost/tests/devtest/benchmark_rate_test.py75
-rwxr-xr-xhost/tests/devtest/devtest_b2xx.py76
-rwxr-xr-xhost/tests/devtest/devtest_x3x0.py57
-rw-r--r--host/tests/devtest/gpio_test.py47
-rwxr-xr-xhost/tests/devtest/run_testsuite.py132
-rwxr-xr-xhost/tests/devtest/rx_samples_to_file_test.py67
-rw-r--r--host/tests/devtest/test_messages_test.py57
-rw-r--r--host/tests/devtest/test_pps_test.py51
-rwxr-xr-xhost/tests/devtest/tx_bursts_test.py63
-rwxr-xr-xhost/tests/devtest/uhd_test_base.py222
-rw-r--r--host/tests/devtest/usrp_probe.py50
27 files changed, 1305 insertions, 575 deletions
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/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/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/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/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/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp
index ffce08567..1d102c7f0 100644
--- a/host/lib/usrp/b200/b200_impl.cpp
+++ b/host/lib/usrp/b200/b200_impl.cpp
@@ -677,10 +677,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 +708,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)
diff --git a/host/lib/usrp/multi_usrp.cpp b/host/lib/usrp/multi_usrp.cpp
index 396237e24..57c593efb 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;
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/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..c770446a6
--- /dev/null
+++ b/host/tests/devtest/CMakeLists.txt
@@ -0,0 +1,40 @@
+# 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 "")
+
+#
+# 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)
+
+# 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..cd777aa18
--- /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 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_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 100644
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..587d1cc64
--- /dev/null
+++ b/host/tests/devtest/run_testsuite.py
@@ -0,0 +1,132 @@
+#!/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)
+ 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]
+ print('--- Done testing all attached devices.')
+
+if __name__ == "__main__":
+ main()
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 100644
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')