summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--host/examples/rx_ascii_art_dft.cpp4
-rw-r--r--host/examples/rx_samples_to_file.cpp4
-rw-r--r--host/examples/rx_samples_to_udp.cpp4
-rw-r--r--host/examples/tx_samples_from_file.cpp4
-rw-r--r--host/examples/tx_waveforms.cpp17
-rw-r--r--host/include/uhd/convert.hpp50
-rw-r--r--host/include/uhd/stream.hpp16
-rw-r--r--host/lib/convert/CMakeLists.txt7
-rw-r--r--host/lib/convert/convert_common.hpp55
-rw-r--r--host/lib/convert/convert_impl.cpp28
-rw-r--r--host/lib/convert/convert_with_tables.cpp188
-rw-r--r--host/lib/convert/gen_convert_general.py21
-rw-r--r--host/lib/transport/super_recv_packet_handler.hpp13
-rw-r--r--host/lib/transport/super_send_packet_handler.hpp13
-rw-r--r--host/tests/convert_test.cpp24
15 files changed, 339 insertions, 109 deletions
diff --git a/host/examples/rx_ascii_art_dft.cpp b/host/examples/rx_ascii_art_dft.cpp
index cba72472a..fe8fb0347 100644
--- a/host/examples/rx_ascii_art_dft.cpp
+++ b/host/examples/rx_ascii_art_dft.cpp
@@ -125,12 +125,12 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
UHD_ASSERT_THROW(lo_locked.to_bool());
}
sensor_names = usrp->get_mboard_sensor_names(0);
- if ((ref == "MIMO") and (std::find(sensor_names.begin(), sensor_names.end(), "mimo_locked") != sensor_names.end())) {
+ if ((ref == "mimo") and (std::find(sensor_names.begin(), sensor_names.end(), "mimo_locked") != sensor_names.end())) {
uhd::sensor_value_t mimo_locked = usrp->get_mboard_sensor("mimo_locked",0);
std::cout << boost::format("Checking RX: %s ...") % mimo_locked.to_pp_string() << std::endl;
UHD_ASSERT_THROW(mimo_locked.to_bool());
}
- if ((ref == "EXTERNAL") and (std::find(sensor_names.begin(), sensor_names.end(), "ref_locked") != sensor_names.end())) {
+ if ((ref == "external") and (std::find(sensor_names.begin(), sensor_names.end(), "ref_locked") != sensor_names.end())) {
uhd::sensor_value_t ref_locked = usrp->get_mboard_sensor("ref_locked",0);
std::cout << boost::format("Checking RX: %s ...") % ref_locked.to_pp_string() << std::endl;
UHD_ASSERT_THROW(ref_locked.to_bool());
diff --git a/host/examples/rx_samples_to_file.cpp b/host/examples/rx_samples_to_file.cpp
index ed242b07a..130009851 100644
--- a/host/examples/rx_samples_to_file.cpp
+++ b/host/examples/rx_samples_to_file.cpp
@@ -170,12 +170,12 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
UHD_ASSERT_THROW(lo_locked.to_bool());
}
sensor_names = usrp->get_mboard_sensor_names(0);
- if ((ref == "MIMO") and (std::find(sensor_names.begin(), sensor_names.end(), "mimo_locked") != sensor_names.end())) {
+ if ((ref == "mimo") and (std::find(sensor_names.begin(), sensor_names.end(), "mimo_locked") != sensor_names.end())) {
uhd::sensor_value_t mimo_locked = usrp->get_mboard_sensor("mimo_locked",0);
std::cout << boost::format("Checking RX: %s ...") % mimo_locked.to_pp_string() << std::endl;
UHD_ASSERT_THROW(mimo_locked.to_bool());
}
- if ((ref == "EXTERNAL") and (std::find(sensor_names.begin(), sensor_names.end(), "ref_locked") != sensor_names.end())) {
+ if ((ref == "external") and (std::find(sensor_names.begin(), sensor_names.end(), "ref_locked") != sensor_names.end())) {
uhd::sensor_value_t ref_locked = usrp->get_mboard_sensor("ref_locked",0);
std::cout << boost::format("Checking RX: %s ...") % ref_locked.to_pp_string() << std::endl;
UHD_ASSERT_THROW(ref_locked.to_bool());
diff --git a/host/examples/rx_samples_to_udp.cpp b/host/examples/rx_samples_to_udp.cpp
index c456f05c3..42b80762f 100644
--- a/host/examples/rx_samples_to_udp.cpp
+++ b/host/examples/rx_samples_to_udp.cpp
@@ -108,12 +108,12 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
UHD_ASSERT_THROW(lo_locked.to_bool());
}
sensor_names = usrp->get_mboard_sensor_names(0);
- if ((ref == "MIMO") and (std::find(sensor_names.begin(), sensor_names.end(), "mimo_locked") != sensor_names.end())) {
+ if ((ref == "mimo") and (std::find(sensor_names.begin(), sensor_names.end(), "mimo_locked") != sensor_names.end())) {
uhd::sensor_value_t mimo_locked = usrp->get_mboard_sensor("mimo_locked",0);
std::cout << boost::format("Checking RX: %s ...") % mimo_locked.to_pp_string() << std::endl;
UHD_ASSERT_THROW(mimo_locked.to_bool());
}
- if ((ref == "EXTERNAL") and (std::find(sensor_names.begin(), sensor_names.end(), "ref_locked") != sensor_names.end())) {
+ if ((ref == "external") and (std::find(sensor_names.begin(), sensor_names.end(), "ref_locked") != sensor_names.end())) {
uhd::sensor_value_t ref_locked = usrp->get_mboard_sensor("ref_locked",0);
std::cout << boost::format("Checking RX: %s ...") % ref_locked.to_pp_string() << std::endl;
UHD_ASSERT_THROW(ref_locked.to_bool());
diff --git a/host/examples/tx_samples_from_file.cpp b/host/examples/tx_samples_from_file.cpp
index 8e3614f6c..ea4add403 100644
--- a/host/examples/tx_samples_from_file.cpp
+++ b/host/examples/tx_samples_from_file.cpp
@@ -150,12 +150,12 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
UHD_ASSERT_THROW(lo_locked.to_bool());
}
sensor_names = usrp->get_mboard_sensor_names(0);
- if ((ref == "MIMO") and (std::find(sensor_names.begin(), sensor_names.end(), "mimo_locked") != sensor_names.end())) {
+ if ((ref == "mimo") and (std::find(sensor_names.begin(), sensor_names.end(), "mimo_locked") != sensor_names.end())) {
uhd::sensor_value_t mimo_locked = usrp->get_mboard_sensor("mimo_locked",0);
std::cout << boost::format("Checking TX: %s ...") % mimo_locked.to_pp_string() << std::endl;
UHD_ASSERT_THROW(mimo_locked.to_bool());
}
- if ((ref == "EXTERNAL") and (std::find(sensor_names.begin(), sensor_names.end(), "ref_locked") != sensor_names.end())) {
+ if ((ref == "external") and (std::find(sensor_names.begin(), sensor_names.end(), "ref_locked") != sensor_names.end())) {
uhd::sensor_value_t ref_locked = usrp->get_mboard_sensor("ref_locked",0);
std::cout << boost::format("Checking TX: %s ...") % ref_locked.to_pp_string() << std::endl;
UHD_ASSERT_THROW(ref_locked.to_bool());
diff --git a/host/examples/tx_waveforms.cpp b/host/examples/tx_waveforms.cpp
index 5b17e0595..2a3d9f8e5 100644
--- a/host/examples/tx_waveforms.cpp
+++ b/host/examples/tx_waveforms.cpp
@@ -75,8 +75,8 @@ public:
}
}
- inline std::complex<float> operator()(const double theta) const{
- return _wave_table[unsigned(theta*wave_table_len)%wave_table_len];
+ inline std::complex<float> operator()(const size_t index) const{
+ return _wave_table[index % wave_table_len];
}
private:
@@ -188,8 +188,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
//pre-compute the waveform values
const wave_table_class wave_table(wave_type, ampl);
- const double cps = wave_freq/usrp->get_tx_rate();
- double theta = 0;
+ const size_t step = boost::math::iround(wave_freq/usrp->get_tx_rate() * wave_table_len);
+ size_t index = 0;
//create a transmit streamer
//linearly map channels (index0 = channel0, index1 = channel1, ...)
@@ -222,12 +222,12 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
UHD_ASSERT_THROW(lo_locked.to_bool());
}
sensor_names = usrp->get_mboard_sensor_names(0);
- if ((ref == "MIMO") and (std::find(sensor_names.begin(), sensor_names.end(), "mimo_locked") != sensor_names.end())) {
+ if ((ref == "mimo") and (std::find(sensor_names.begin(), sensor_names.end(), "mimo_locked") != sensor_names.end())) {
uhd::sensor_value_t mimo_locked = usrp->get_mboard_sensor("mimo_locked",0);
std::cout << boost::format("Checking TX: %s ...") % mimo_locked.to_pp_string() << std::endl;
UHD_ASSERT_THROW(mimo_locked.to_bool());
}
- if ((ref == "EXTERNAL") and (std::find(sensor_names.begin(), sensor_names.end(), "ref_locked") != sensor_names.end())) {
+ if ((ref == "external") and (std::find(sensor_names.begin(), sensor_names.end(), "ref_locked") != sensor_names.end())) {
uhd::sensor_value_t ref_locked = usrp->get_mboard_sensor("ref_locked",0);
std::cout << boost::format("Checking TX: %s ...") % ref_locked.to_pp_string() << std::endl;
UHD_ASSERT_THROW(ref_locked.to_bool());
@@ -240,12 +240,9 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
while(not stop_signal_called){
//fill the buffer with the waveform
for (size_t n = 0; n < buff.size(); n++){
- buff[n] = wave_table(theta += cps);
+ buff[n] = wave_table(index += step);
}
- //bring the theta back into range [0, 1)
- theta = std::fmod(theta, 1);
-
//send the entire contents of the buffer
tx_stream->send(buffs, buff.size(), md);
diff --git a/host/include/uhd/convert.hpp b/host/include/uhd/convert.hpp
index c42edfdec..f906ff0e9 100644
--- a/host/include/uhd/convert.hpp
+++ b/host/include/uhd/convert.hpp
@@ -20,33 +20,39 @@
#include <uhd/config.hpp>
#include <uhd/types/ref_vector.hpp>
+#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
#include <boost/operators.hpp>
#include <string>
namespace uhd{ namespace convert{
- typedef uhd::ref_vector<void *> output_type;
- typedef uhd::ref_vector<const void *> input_type;
+ //! A conversion class that implements a conversion from inputs -> outputs.
+ class converter{
+ public:
+ typedef boost::shared_ptr<converter> sptr;
+ typedef uhd::ref_vector<void *> output_type;
+ typedef uhd::ref_vector<const void *> input_type;
- //! input vectors, output vectors, num samples, scale factor
- typedef boost::function<void(const input_type&, const output_type&, const size_t, const double)> function_type;
+ //! Set the scale factor (used in floating point conversions)
+ virtual void set_scalar(const double) = 0;
- /*!
- * Describe the priority of a converter function.
- * A higher priority function takes precedence.
- * The general case function are the lowest.
- * Next comes the liborc implementations.
- * Custom intrinsics implementations are highest.
- */
- enum priority_type{
- PRIORITY_GENERAL = 0,
- PRIORITY_LIBORC = 1,
- PRIORITY_SIMD = 2,
- PRIORITY_CUSTOM = 3,
- PRIORITY_EMPTY = -1,
+ //! The public conversion method to convert inputs -> outputs
+ UHD_INLINE void conv(const input_type &in, const output_type &out, const size_t num){
+ if (num != 0) (*this)(in, out, num);
+ }
+
+ private:
+ //! Callable method: input vectors, output vectors, num samples
+ virtual void operator()(const input_type&, const output_type&, const size_t) = 0;
};
+ //! Conversion factory function typedef
+ typedef boost::function<converter::sptr(void)> function_type;
+
+ //! Priority of conversion routines
+ typedef int priority_type;
+
//! Identify a conversion routine in the registry
struct id_type : boost::equality_comparable<id_type>{
std::string input_format;
@@ -62,19 +68,19 @@ namespace uhd{ namespace convert{
/*!
* Register a converter function.
* \param id identify the conversion
- * \param fcn a pointer to the converter
+ * \param fcn makes a new converter
* \param prio the function priority
*/
UHD_API void register_converter(
const id_type &id,
- function_type fcn,
- priority_type prio
+ const function_type &fcn,
+ const priority_type prio
);
/*!
- * Get a converter function.
+ * Get a converter factory function.
* \param id identify the conversion
- * \return the converter function
+ * \return the converter factory function
*/
UHD_API function_type get_converter(const id_type &id);
diff --git a/host/include/uhd/stream.hpp b/host/include/uhd/stream.hpp
index 1f0332088..8f3219dbd 100644
--- a/host/include/uhd/stream.hpp
+++ b/host/include/uhd/stream.hpp
@@ -49,10 +49,12 @@ struct UHD_API stream_args_t{
/*!
* The CPU format is a string that describes the format of host memory.
- * Common CPU formats are:
- * - fc32 - complex<float>
+ * Conversions for the following CPU formats have been implemented:
* - fc64 - complex<double>
+ * - fc32 - complex<float>
* - sc16 - complex<int16_t>
+ *
+ * The following are not implemented, but are listed to demonstrate naming convention:
* - sc8 - complex<int8_t>
* - f32 - float
* - f64 - double
@@ -63,9 +65,11 @@ struct UHD_API stream_args_t{
/*!
* The OTW format is a string that describes the format over-the-wire.
- * Common OTW format are:
+ * The following over-the-wire formats have been implemented:
* - sc16 - Q16 I16
* - sc8 - Q8_1 I8_1 Q8_0 I8_0
+ *
+ * The following are not implemented, but are listed to demonstrate naming convention:
* - s16 - R16_1 R16_0
* - s8 - R8_3 R8_2 R8_1 R8_0
*/
@@ -74,7 +78,11 @@ struct UHD_API stream_args_t{
/*!
* The args parameter is used to pass arbitrary key/value pairs.
* Possible keys used by args (depends on implementation):
- * - scaler: 8sc converter scaling factor
+ * - scalar: an integer scaling factor used with the sc8 wire format.
+ * The key/value pair scalar=1024 means that the sample in the DSP
+ * was multiplied by 1024 before its upper 8 bits were harvested.
+ *
+ * The following are not implemented, but are listed for conceptual purposes:
* - function: magnitude or phase/magnitude
* - units: numeric units like counts or dBm
*/
diff --git a/host/lib/convert/CMakeLists.txt b/host/lib/convert/CMakeLists.txt
index 4cc421884..98907dc29 100644
--- a/host/lib/convert/CMakeLists.txt
+++ b/host/lib/convert/CMakeLists.txt
@@ -91,11 +91,7 @@ IF(CMAKE_COMPILER_IS_GNUCXX)
UNSET(CMAKE_REQUIRED_FLAGS)
ENDIF(CMAKE_COMPILER_IS_GNUCXX)
-IF(HAVE_ARM_NEON_H AND ENABLE_ORC)
- #prefer orc support, its faster than the current intrinsic implementations
- MESSAGE(STATUS "Enabled conversion support with ORC.")
-ELSEIF(HAVE_ARM_NEON_H)
- MESSAGE(STATUS "Enabled conversion support with NEON intrinsics.")
+IF(HAVE_ARM_NEON_H)
SET_SOURCE_FILES_PROPERTIES(
${CMAKE_CURRENT_SOURCE_DIR}/convert_with_neon.cpp
PROPERTIES COMPILE_FLAGS "${NEON_FLAGS}"
@@ -117,5 +113,6 @@ LIBUHD_PYTHON_GEN_SOURCE(
)
LIBUHD_APPEND_SOURCES(
+ ${CMAKE_CURRENT_SOURCE_DIR}/convert_with_tables.cpp
${CMAKE_CURRENT_SOURCE_DIR}/convert_impl.cpp
)
diff --git a/host/lib/convert/convert_common.hpp b/host/lib/convert/convert_common.hpp
index 34fb848c3..699d6301b 100644
--- a/host/lib/convert/convert_common.hpp
+++ b/host/lib/convert/convert_common.hpp
@@ -23,28 +23,43 @@
#include <boost/cstdint.hpp>
#include <complex>
-#define _DECLARE_CONVERTER(fcn, in_form, num_in, out_form, num_out, prio) \
- static void fcn( \
- const uhd::convert::input_type &inputs, \
- const uhd::convert::output_type &outputs, \
- const size_t nsamps, const double scale_factor \
- ); \
- UHD_STATIC_BLOCK(__register_##fcn##_##prio){ \
+#define _DECLARE_CONVERTER(name, in_form, num_in, out_form, num_out, prio) \
+ struct name : public uhd::convert::converter{ \
+ static sptr make(void){return sptr(new name());} \
+ double scale_factor; \
+ void set_scalar(const double s){scale_factor = s;} \
+ void operator()(const input_type&, const output_type&, const size_t); \
+ }; \
+ UHD_STATIC_BLOCK(__register_##name##_##prio){ \
uhd::convert::id_type id; \
id.input_format = #in_form; \
id.num_inputs = num_in; \
id.output_format = #out_form; \
id.num_outputs = num_out; \
- uhd::convert::register_converter(id, fcn, prio); \
+ uhd::convert::register_converter(id, &name::make, prio); \
} \
- static void fcn( \
- const uhd::convert::input_type &inputs, \
- const uhd::convert::output_type &outputs, \
- const size_t nsamps, const double scale_factor \
+ void name::operator()( \
+ const input_type &inputs, const output_type &outputs, const size_t nsamps \
)
#define DECLARE_CONVERTER(in_form, num_in, out_form, num_out, prio) \
- _DECLARE_CONVERTER(__convert_##in_form##_##num_in##_##out_form##_##num_out, in_form, num_in, out_form, num_out, prio)
+ _DECLARE_CONVERTER(__convert_##in_form##_##num_in##_##out_form##_##num_out##_##prio, in_form, num_in, out_form, num_out, prio)
+
+/***********************************************************************
+ * Setup priorities
+ **********************************************************************/
+static const int PRIORITY_GENERAL = 0;
+static const int PRIORITY_EMPTY = -1;
+
+#ifdef __ARM_NEON__
+static const int PRIORITY_LIBORC = 3;
+static const int PRIORITY_SIMD = 1; //neon conversions could be implemented better, orc wins
+static const int PRIORITY_TABLE = 2; //tables require large cache, so they are slower on arm
+#else
+static const int PRIORITY_LIBORC = 1;
+static const int PRIORITY_SIMD = 2;
+static const int PRIORITY_TABLE = 3;
+#endif
/***********************************************************************
* Typedefs
@@ -120,6 +135,20 @@ static UHD_INLINE fc64_t item32_sc16_to_fc64(item32_t item, double scale_factor)
}
/***********************************************************************
+ * Convert items32 sc8 buffer to complex char
+ **********************************************************************/
+static UHD_INLINE void item32_sc8_to_sc8(item32_t item, sc8_t &out0, sc8_t &out1, double){
+ out0 = sc8_t(
+ boost::int8_t(item >> 8),
+ boost::int8_t(item >> 0)
+ );
+ out1 = sc8_t(
+ boost::int8_t(item >> 24),
+ boost::int8_t(item >> 16)
+ );
+}
+
+/***********************************************************************
* Convert items32 sc8 buffer to complex short
**********************************************************************/
static UHD_INLINE void item32_sc8_to_sc16(item32_t item, sc16_t &out0, sc16_t &out1, double){
diff --git a/host/lib/convert/convert_impl.cpp b/host/lib/convert/convert_impl.cpp
index df03b44f9..12ad54486 100644
--- a/host/lib/convert/convert_impl.cpp
+++ b/host/lib/convert/convert_impl.cpp
@@ -69,8 +69,8 @@ UHD_SINGLETON_FCN(fcn_table_type, get_table);
**********************************************************************/
void uhd::convert::register_converter(
const id_type &id,
- function_type fcn,
- priority_type prio
+ const function_type &fcn,
+ const priority_type prio
){
//get a reference to the function table
fcn_table_type &table = get_table();
@@ -103,7 +103,7 @@ convert::function_type convert::get_converter(const id_type &id){
typedef uhd::dict<std::string, size_t> item_size_type;
UHD_SINGLETON_FCN(item_size_type, get_item_size_table);
-void register_bytes_per_item(
+void convert::register_bytes_per_item(
const std::string &format, const size_t size
){
get_item_size_table()[format] = size;
@@ -126,16 +126,18 @@ size_t convert::get_bytes_per_item(const std::string &format){
UHD_STATIC_BLOCK(convert_register_item_sizes){
//register standard complex types
- get_item_size_table()["fc64"] = sizeof(std::complex<double>);
- get_item_size_table()["fc32"] = sizeof(std::complex<float>);
- get_item_size_table()["sc32"] = sizeof(std::complex<boost::int32_t>);
- get_item_size_table()["sc16"] = sizeof(std::complex<boost::int16_t>);
- get_item_size_table()["sc8"] = sizeof(std::complex<boost::int8_t>);
+ convert::register_bytes_per_item("fc64", sizeof(std::complex<double>));
+ convert::register_bytes_per_item("fc32", sizeof(std::complex<float>));
+ convert::register_bytes_per_item("sc64", sizeof(std::complex<boost::int64_t>));
+ convert::register_bytes_per_item("sc32", sizeof(std::complex<boost::int32_t>));
+ convert::register_bytes_per_item("sc16", sizeof(std::complex<boost::int16_t>));
+ convert::register_bytes_per_item("sc8", sizeof(std::complex<boost::int8_t>));
//register standard real types
- get_item_size_table()["f64"] = sizeof(double);
- get_item_size_table()["f32"] = sizeof(float);
- get_item_size_table()["s32"] = sizeof(boost::int32_t);
- get_item_size_table()["s16"] = sizeof(boost::int16_t);
- get_item_size_table()["s8"] = sizeof(boost::int8_t);
+ convert::register_bytes_per_item("f64", sizeof(double));
+ convert::register_bytes_per_item("f32", sizeof(float));
+ convert::register_bytes_per_item("s64", sizeof(boost::int64_t));
+ convert::register_bytes_per_item("s32", sizeof(boost::int32_t));
+ convert::register_bytes_per_item("s16", sizeof(boost::int16_t));
+ convert::register_bytes_per_item("s8", sizeof(boost::int8_t));
}
diff --git a/host/lib/convert/convert_with_tables.cpp b/host/lib/convert/convert_with_tables.cpp
new file mode 100644
index 000000000..c45415d5d
--- /dev/null
+++ b/host/lib/convert/convert_with_tables.cpp
@@ -0,0 +1,188 @@
+//
+// Copyright 2011 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 "convert_common.hpp"
+#include <uhd/utils/byteswap.hpp>
+#include <vector>
+
+using namespace uhd::convert;
+
+static const size_t sc16_table_len = size_t(1 << 16);
+
+typedef boost::uint16_t (*tohost16_type)(boost::uint16_t);
+
+/***********************************************************************
+ * Implementation for sc16 lookup table
+ * - Lookup the real and imaginary parts individually
+ **********************************************************************/
+template <typename type, tohost16_type tohost, size_t re_shift, size_t im_shift>
+class convert_sc16_item32_1_to_fcxx_1 : public converter{
+public:
+ convert_sc16_item32_1_to_fcxx_1(void): _table(sc16_table_len){}
+
+ void set_scalar(const double scalar){
+ for (size_t i = 0; i < sc16_table_len; i++){
+ const boost::uint16_t val = tohost(boost::uint16_t(i & 0xffff));
+ _table[i] = type(boost::int16_t(val)*scalar);
+ }
+ }
+
+ void operator()(const input_type &inputs, const output_type &outputs, const size_t nsamps){
+ const item32_t *input = reinterpret_cast<const item32_t *>(inputs[0]);
+ std::complex<type> *output = reinterpret_cast<std::complex<type> *>(outputs[0]);
+
+ for (size_t i = 0; i < nsamps; i++){
+ const item32_t item = input[i];
+ output[i] = std::complex<type>(
+ _table[boost::uint16_t(item >> re_shift)],
+ _table[boost::uint16_t(item >> im_shift)]
+ );
+ }
+ }
+
+private:
+ std::vector<type> _table;
+};
+
+/***********************************************************************
+ * Implementation for sc8 lookup table
+ * - Lookup the real and imaginary parts together
+ **********************************************************************/
+template <typename type, tohost16_type tohost, size_t lo_shift, size_t hi_shift>
+class convert_sc8_item32_1_to_fcxx_1 : public converter{
+public:
+ convert_sc8_item32_1_to_fcxx_1(void): _table(sc16_table_len){}
+
+ void set_scalar(const double scalar){
+ for (size_t i = 0; i < sc16_table_len; i++){
+ const boost::uint16_t val = tohost(boost::uint16_t(i & 0xffff));
+ const type real = type(boost::int8_t(val >> 8)*scalar);
+ const type imag = type(boost::int8_t(val >> 0)*scalar);
+ _table[i] = std::complex<type>(real, imag);
+ }
+ }
+
+ void operator()(const input_type &inputs, const output_type &outputs, const size_t nsamps){
+ const item32_t *input = reinterpret_cast<const item32_t *>(size_t(inputs[0]) & ~0x3);
+ std::complex<type> *output = reinterpret_cast<std::complex<type> *>(outputs[0]);
+
+ size_t num_samps = nsamps;
+
+ if ((size_t(inputs[0]) & 0x3) != 0){
+ const item32_t item0 = *input++;
+ *output++ = _table[boost::uint16_t(item0 >> hi_shift)];
+ num_samps--;
+ }
+
+ const size_t num_pairs = num_samps/2;
+ for (size_t i = 0, j = 0; i < num_pairs; i++, j+=2){
+ const item32_t item_i = (input[i]);
+ output[j] = _table[boost::uint16_t(item_i >> lo_shift)];
+ output[j + 1] = _table[boost::uint16_t(item_i >> hi_shift)];
+ }
+
+ if (num_samps != num_pairs*2){
+ const item32_t item_n = input[num_pairs];
+ output[num_samps-1] = _table[boost::uint16_t(item_n >> lo_shift)];
+ }
+ }
+
+private:
+ std::vector<std::complex<type> > _table;
+};
+
+/***********************************************************************
+ * Factory functions and registration
+ **********************************************************************/
+
+#ifdef BOOST_BIG_ENDIAN
+# define SHIFT_PAIR0 16, 0
+# define SHIFT_PAIR1 0, 16
+#else
+# define SHIFT_PAIR0 0, 16
+# define SHIFT_PAIR1 16, 0
+#endif
+
+static converter::sptr make_convert_sc16_item32_be_1_to_fc32_1(void){
+ return converter::sptr(new convert_sc16_item32_1_to_fcxx_1<float, uhd::ntohx, SHIFT_PAIR0>());
+}
+
+static converter::sptr make_convert_sc16_item32_be_1_to_fc64_1(void){
+ return converter::sptr(new convert_sc16_item32_1_to_fcxx_1<double, uhd::ntohx, SHIFT_PAIR0>());
+}
+
+static converter::sptr make_convert_sc16_item32_le_1_to_fc32_1(void){
+ return converter::sptr(new convert_sc16_item32_1_to_fcxx_1<float, uhd::wtohx, SHIFT_PAIR1>());
+}
+
+static converter::sptr make_convert_sc16_item32_le_1_to_fc64_1(void){
+ return converter::sptr(new convert_sc16_item32_1_to_fcxx_1<double, uhd::wtohx, SHIFT_PAIR1>());
+}
+
+static converter::sptr make_convert_sc8_item32_be_1_to_fc32_1(void){
+ return converter::sptr(new convert_sc8_item32_1_to_fcxx_1<float, uhd::ntohx, SHIFT_PAIR1>());
+}
+
+static converter::sptr make_convert_sc8_item32_be_1_to_fc64_1(void){
+ return converter::sptr(new convert_sc8_item32_1_to_fcxx_1<double, uhd::ntohx, SHIFT_PAIR1>());
+}
+
+static converter::sptr make_convert_sc8_item32_le_1_to_fc32_1(void){
+ return converter::sptr(new convert_sc8_item32_1_to_fcxx_1<float, uhd::wtohx, SHIFT_PAIR0>());
+}
+
+static converter::sptr make_convert_sc8_item32_le_1_to_fc64_1(void){
+ return converter::sptr(new convert_sc8_item32_1_to_fcxx_1<double, uhd::wtohx, SHIFT_PAIR0>());
+}
+
+UHD_STATIC_BLOCK(register_convert_sc16_item32_1_to_fcxx_1){
+ uhd::convert::id_type id;
+ id.num_inputs = 1;
+ id.num_outputs = 1;
+
+ id.output_format = "fc32";
+ id.input_format = "sc16_item32_be";
+ uhd::convert::register_converter(id, &make_convert_sc16_item32_be_1_to_fc32_1, PRIORITY_TABLE);
+
+ id.output_format = "fc64";
+ id.input_format = "sc16_item32_be";
+ uhd::convert::register_converter(id, &make_convert_sc16_item32_be_1_to_fc64_1, PRIORITY_TABLE);
+
+ id.output_format = "fc32";
+ id.input_format = "sc16_item32_le";
+ uhd::convert::register_converter(id, &make_convert_sc16_item32_le_1_to_fc32_1, PRIORITY_TABLE);
+
+ id.output_format = "fc64";
+ id.input_format = "sc16_item32_le";
+ uhd::convert::register_converter(id, &make_convert_sc16_item32_le_1_to_fc64_1, PRIORITY_TABLE);
+
+ id.output_format = "fc32";
+ id.input_format = "sc8_item32_be";
+ uhd::convert::register_converter(id, &make_convert_sc8_item32_be_1_to_fc32_1, PRIORITY_TABLE);
+
+ id.output_format = "fc64";
+ id.input_format = "sc8_item32_be";
+ uhd::convert::register_converter(id, &make_convert_sc8_item32_be_1_to_fc64_1, PRIORITY_TABLE);
+
+ id.output_format = "fc32";
+ id.input_format = "sc8_item32_le";
+ uhd::convert::register_converter(id, &make_convert_sc8_item32_le_1_to_fc32_1, PRIORITY_TABLE);
+
+ id.output_format = "fc64";
+ id.input_format = "sc8_item32_le";
+ uhd::convert::register_converter(id, &make_convert_sc8_item32_le_1_to_fc64_1, PRIORITY_TABLE);
+}
diff --git a/host/lib/convert/gen_convert_general.py b/host/lib/convert/gen_convert_general.py
index 52b4212b4..b8d64aa4b 100644
--- a/host/lib/convert/gen_convert_general.py
+++ b/host/lib/convert/gen_convert_general.py
@@ -33,8 +33,6 @@ DECLARE_CONVERTER(item32, 1, sc16_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]);
- if (scale_factor == 0){} //avoids unused warning
-
for (size_t i = 0; i < nsamps; i++){
output[i] = $(to_wire)(input[i]);
}
@@ -44,15 +42,13 @@ DECLARE_CONVERTER(sc16_item32_$(end), 1, item32, 1, PRIORITY_GENERAL){
const item32_t *input = reinterpret_cast<const item32_t *>(inputs[0]);
item32_t *output = reinterpret_cast<item32_t *>(outputs[0]);
- if (scale_factor == 0){} //avoids unused warning
-
for (size_t i = 0; i < nsamps; i++){
output[i] = $(to_host)(input[i]);
}
}
"""
-TMPL_CONV_GEN2_COMPLEX = """
+TMPL_CONV_GEN2_SC16 = """
DECLARE_CONVERTER($(cpu_type), 1, sc16_item32_$(end), 1, PRIORITY_GENERAL){
const $(cpu_type)_t *input = reinterpret_cast<const $(cpu_type)_t *>(inputs[0]);
item32_t *output = reinterpret_cast<item32_t *>(outputs[0]);
@@ -70,7 +66,9 @@ DECLARE_CONVERTER(sc16_item32_$(end), 1, $(cpu_type), 1, PRIORITY_GENERAL){
output[i] = item32_sc16_to_$(cpu_type)($(to_host)(input[i]), scale_factor);
}
}
+"""
+TMPL_CONV_GEN2_SC8 = """
DECLARE_CONVERTER(sc8_item32_$(end), 1, $(cpu_type), 1, PRIORITY_GENERAL){
const item32_t *input = reinterpret_cast<const item32_t *>(size_t(inputs[0]) & ~0x3);
$(cpu_type)_t *output = reinterpret_cast<$(cpu_type)_t *>(outputs[0]);
@@ -103,8 +101,6 @@ DECLARE_CONVERTER($(cpu_type), $(width), sc16_item16_usrp1, 1, PRIORITY_GENERAL)
#end for
boost::uint16_t *output = reinterpret_cast<boost::uint16_t *>(outputs[0]);
- if (scale_factor == 0){} //avoids unused warning
-
for (size_t i = 0, j = 0; i < nsamps; i++){
#for $w in range($width)
output[j++] = $(to_wire)(boost::int16_t(input$(w)[i].real()$(do_scale)));
@@ -119,8 +115,6 @@ DECLARE_CONVERTER(sc16_item16_usrp1, 1, $(cpu_type), $(width), PRIORITY_GENERAL)
$(cpu_type)_t *output$(w) = reinterpret_cast<$(cpu_type)_t *>(outputs[$(w)]);
#end for
- if (scale_factor == 0){} //avoids unused warning
-
for (size_t i = 0, j = 0; i < nsamps; i++){
#for $w in range($width)
output$(w)[i] = $(cpu_type)_t(
@@ -138,8 +132,6 @@ DECLARE_CONVERTER(sc8_item16_usrp1, 1, $(cpu_type), $(width), PRIORITY_GENERAL){
$(cpu_type)_t *output$(w) = reinterpret_cast<$(cpu_type)_t *>(outputs[$(w)]);
#end for
- if (scale_factor == 0){} //avoids unused warning
-
for (size_t i = 0, j = 0; i < nsamps; i++){
#for $w in range($width)
{
@@ -170,7 +162,12 @@ if __name__ == '__main__':
):
for cpu_type in 'fc64', 'fc32', 'sc16':
output += parse_tmpl(
- TMPL_CONV_GEN2_COMPLEX,
+ TMPL_CONV_GEN2_SC16,
+ end=end, to_host=to_host, to_wire=to_wire, cpu_type=cpu_type
+ )
+ for cpu_type in 'fc64', 'fc32', 'sc16', 'sc8':
+ output += parse_tmpl(
+ TMPL_CONV_GEN2_SC8,
end=end, to_host=to_host, to_wire=to_wire, cpu_type=cpu_type
)
output += parse_tmpl(
diff --git a/host/lib/transport/super_recv_packet_handler.hpp b/host/lib/transport/super_recv_packet_handler.hpp
index 57aae96b1..05cad93ea 100644
--- a/host/lib/transport/super_recv_packet_handler.hpp
+++ b/host/lib/transport/super_recv_packet_handler.hpp
@@ -71,7 +71,6 @@ public:
{
this->resize(size);
set_alignment_failure_threshold(1000);
- this->set_scale_factor(1/32767.);
}
//! Resize the number of transport channels
@@ -124,7 +123,8 @@ public:
//! Set the conversion routine for all channels
void set_converter(const uhd::convert::id_type &id){
_io_buffs.resize(id.num_outputs);
- _converter = uhd::convert::get_converter(id);
+ _converter = uhd::convert::get_converter(id)();
+ this->set_scale_factor(1/32767.); //update after setting converter
_bytes_per_otw_item = uhd::convert::get_bytes_per_item(id.input_format);
_bytes_per_cpu_item = uhd::convert::get_bytes_per_item(id.output_format);
}
@@ -136,7 +136,7 @@ public:
//! Set the scale factor used in float conversion
void set_scale_factor(const double scale_factor){
- _scale_factor = scale_factor;
+ _converter->set_scalar(scale_factor);
}
/*******************************************************************
@@ -207,8 +207,7 @@ private:
std::vector<void *> _io_buffs; //used in conversion
size_t _bytes_per_otw_item; //used in conversion
size_t _bytes_per_cpu_item; //used in conversion
- uhd::convert::function_type _converter; //used in conversion
- double _scale_factor;
+ uhd::convert::converter::sptr _converter; //used in conversion
//! information stored for a received buffer
struct per_buffer_info_type{
@@ -523,9 +522,7 @@ private:
}
//copy-convert the samples from the recv buffer
- if (nsamps_to_copy_per_io_buff != 0) _converter(
- buff_info.copy_buff, _io_buffs, nsamps_to_copy_per_io_buff, _scale_factor
- );
+ _converter->conv(buff_info.copy_buff, _io_buffs, nsamps_to_copy_per_io_buff);
//update the rx copy buffer to reflect the bytes copied
buff_info.copy_buff += bytes_to_copy;
diff --git a/host/lib/transport/super_send_packet_handler.hpp b/host/lib/transport/super_send_packet_handler.hpp
index c3ffcc861..5ed8e0143 100644
--- a/host/lib/transport/super_send_packet_handler.hpp
+++ b/host/lib/transport/super_send_packet_handler.hpp
@@ -56,7 +56,6 @@ public:
_next_packet_seq(0)
{
this->resize(size);
- this->set_scale_factor(32767.);
}
//! Resize the number of transport channels
@@ -100,7 +99,8 @@ public:
//! Set the conversion routine for all channels
void set_converter(const uhd::convert::id_type &id){
_io_buffs.resize(id.num_inputs);
- _converter = uhd::convert::get_converter(id);
+ _converter = uhd::convert::get_converter(id)();
+ this->set_scale_factor(32767.); //update after setting converter
_bytes_per_otw_item = uhd::convert::get_bytes_per_item(id.output_format);
_bytes_per_cpu_item = uhd::convert::get_bytes_per_item(id.input_format);
}
@@ -116,7 +116,7 @@ public:
//! Set the scale factor used in float conversion
void set_scale_factor(const double scale_factor){
- _scale_factor = scale_factor;
+ _converter->set_scalar(scale_factor);
}
/*******************************************************************
@@ -202,11 +202,10 @@ private:
std::vector<const void *> _io_buffs; //used in conversion
size_t _bytes_per_otw_item; //used in conversion
size_t _bytes_per_cpu_item; //used in conversion
- uhd::convert::function_type _converter; //used in conversion
+ uhd::convert::converter::sptr _converter; //used in conversion
size_t _max_samples_per_packet;
std::vector<const void *> _zero_buffs;
size_t _next_packet_seq;
- double _scale_factor;
/*******************************************************************
* Send a single packet:
@@ -239,9 +238,7 @@ private:
otw_mem += if_packet_info.num_header_words32;
//copy-convert the samples into the send buffer
- if (nsamps_per_buff != 0) _converter(
- _io_buffs, otw_mem, nsamps_per_buff, _scale_factor
- );
+ _converter->conv(_io_buffs, otw_mem, nsamps_per_buff);
//commit the samples to the zero-copy interface
size_t num_bytes_total = (_header_offset_words32+if_packet_info.num_packet_words32)*sizeof(boost::uint32_t);
diff --git a/host/tests/convert_test.cpp b/host/tests/convert_test.cpp
index b63ff6752..1a5d30080 100644
--- a/host/tests/convert_test.cpp
+++ b/host/tests/convert_test.cpp
@@ -53,10 +53,14 @@ template <typename Range> static void loopback(
std::vector<void *> output0(1, &interm[0]), output1(1, &output[0]);
//convert to intermediate type
- convert::get_converter(in_id)(input0, output0, nsamps, 32767.);
+ convert::converter::sptr c0 = convert::get_converter(in_id)();
+ c0->set_scalar(32767.);
+ c0->conv(input0, output0, nsamps);
//convert back to host type
- convert::get_converter(out_id)(input1, output1, nsamps, 1/32767.);
+ convert::converter::sptr c1 = convert::get_converter(out_id)();
+ c1->set_scalar(1/32767.);
+ c1->conv(input1, output1, nsamps);
}
/***********************************************************************
@@ -216,10 +220,14 @@ BOOST_AUTO_TEST_CASE(test_convert_types_fc32_to_sc16){
std::vector<void *> output0(1, &interm[0]), output1(1, &output[0]);
//convert float to intermediate
- convert::get_converter(in_id)(input0, output0, nsamps, 32767.);
+ convert::converter::sptr c0 = convert::get_converter(in_id)();
+ c0->set_scalar(32767.);
+ c0->conv(input0, output0, nsamps);
//convert intermediate to short
- convert::get_converter(out_id)(input1, output1, nsamps, 1/32767.);
+ convert::converter::sptr c1 = convert::get_converter(out_id)();
+ c1->set_scalar(1/32767.);
+ c1->conv(input1, output1, nsamps);
//test that the inputs and outputs match
for (size_t i = 0; i < nsamps; i++){
@@ -257,10 +265,14 @@ BOOST_AUTO_TEST_CASE(test_convert_types_sc16_to_fc32){
std::vector<void *> output0(1, &interm[0]), output1(1, &output[0]);
//convert short to intermediate
- convert::get_converter(in_id)(input0, output0, nsamps, 32767.);
+ convert::converter::sptr c0 = convert::get_converter(in_id)();
+ c0->set_scalar(32767.);
+ c0->conv(input0, output0, nsamps);
//convert intermediate to float
- convert::get_converter(out_id)(input1, output1, nsamps, 1/32767.);
+ convert::converter::sptr c1 = convert::get_converter(out_id)();
+ c1->set_scalar(1/32767.);
+ c1->conv(input1, output1, nsamps);
//test that the inputs and outputs match
for (size_t i = 0; i < nsamps; i++){