diff options
-rw-r--r-- | host/examples/rx_ascii_art_dft.cpp | 4 | ||||
-rw-r--r-- | host/examples/rx_samples_to_file.cpp | 4 | ||||
-rw-r--r-- | host/examples/rx_samples_to_udp.cpp | 4 | ||||
-rw-r--r-- | host/examples/tx_samples_from_file.cpp | 4 | ||||
-rw-r--r-- | host/examples/tx_waveforms.cpp | 17 | ||||
-rw-r--r-- | host/include/uhd/convert.hpp | 50 | ||||
-rw-r--r-- | host/include/uhd/stream.hpp | 16 | ||||
-rw-r--r-- | host/lib/convert/CMakeLists.txt | 7 | ||||
-rw-r--r-- | host/lib/convert/convert_common.hpp | 55 | ||||
-rw-r--r-- | host/lib/convert/convert_impl.cpp | 28 | ||||
-rw-r--r-- | host/lib/convert/convert_with_tables.cpp | 188 | ||||
-rw-r--r-- | host/lib/convert/gen_convert_general.py | 21 | ||||
-rw-r--r-- | host/lib/transport/super_recv_packet_handler.hpp | 13 | ||||
-rw-r--r-- | host/lib/transport/super_send_packet_handler.hpp | 13 | ||||
-rw-r--r-- | host/tests/convert_test.cpp | 24 |
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++){ |