diff options
| -rw-r--r-- | host/lib/convert/convert_pack_sc12.cpp | 91 | ||||
| -rw-r--r-- | host/lib/convert/convert_unpack_sc12.cpp | 50 | ||||
| -rw-r--r-- | host/tests/convert_test.cpp | 31 | ||||
| -rw-r--r-- | host/utils/converter_benchmark.cpp | 24 | 
4 files changed, 169 insertions, 27 deletions
| diff --git a/host/lib/convert/convert_pack_sc12.cpp b/host/lib/convert/convert_pack_sc12.cpp index aaa6f2632..2e45e19f5 100644 --- a/host/lib/convert/convert_pack_sc12.cpp +++ b/host/lib/convert/convert_pack_sc12.cpp @@ -20,6 +20,7 @@  #include <uhd/utils/log.hpp>  #include <boost/math/special_functions/round.hpp>  #include <vector> +#include <type_traits>  using namespace uhd::convert; @@ -59,6 +60,17 @@ enum item32_sc12_3x_enable {   * |_ _|_ _ _4_ _ _| 2   * 31              0   */ +template <towire32_type towire> +inline void pack(item32_sc12_3x &output, int enable, const int32_t i[4], const int32_t q[4]) +{ +    if (enable & CONVERT12_LINE0) +        output.line0 = towire(i[0] << 20 | q[0] <<  8 | i[1] >> 4); +    if (enable & CONVERT12_LINE1) +        output.line1 = towire(i[1] << 28 | q[1] << 16 | i[2] << 4 | q[2] >> 8); +    if (enable & CONVERT12_LINE2) +        output.line2 = towire(q[2] << 24 | i[3] << 12 | q[3]); +} +  template <typename type, towire32_type towire>  void convert_star_4_to_sc12_item32_3  ( @@ -68,31 +80,55 @@ void convert_star_4_to_sc12_item32_3      const std::complex<type> &in3,      const int enable,      item32_sc12_3x &output, -    const double scalar +    const double scalar, +    typename std::enable_if<std::is_floating_point<type>::value>::type* = NULL  )  { -    const item32_t i0 = int32_t(type(in0.real()*scalar)) & 0xfff; -    const item32_t q0 = int32_t(type(in0.imag()*scalar)) & 0xfff; +    int32_t i[4] { +        int32_t(in0.real()*scalar) & 0xfff, +        int32_t(in1.real()*scalar) & 0xfff, +        int32_t(in2.real()*scalar) & 0xfff, +        int32_t(in3.real()*scalar) & 0xfff, +    }; -    const item32_t i1 = int32_t(type(in1.real()*scalar)) & 0xfff; -    const item32_t q1 = int32_t(type(in1.imag()*scalar)) & 0xfff; +    int32_t q[4] { +        int32_t(in0.imag()*scalar) & 0xfff, +        int32_t(in1.imag()*scalar) & 0xfff, +        int32_t(in2.imag()*scalar) & 0xfff, +        int32_t(in3.imag()*scalar) & 0xfff, +    }; -    const item32_t i2 = int32_t(type(in2.real()*scalar)) & 0xfff; -    const item32_t q2 = int32_t(type(in2.imag()*scalar)) & 0xfff; +    pack<towire>(output, enable, i, q); +} -    const item32_t i3 = int32_t(type(in3.real()*scalar)) & 0xfff; -    const item32_t q3 = int32_t(type(in3.imag()*scalar)) & 0xfff; +template <typename type, towire32_type towire> +void convert_star_4_to_sc12_item32_3 +( +    const std::complex<type> &in0, +    const std::complex<type> &in1, +    const std::complex<type> &in2, +    const std::complex<type> &in3, +    const int enable, +    item32_sc12_3x &output, +    const double, +    typename std::enable_if<std::is_same<type, short>::value>::type* = NULL +) +{ +    int32_t i[4] { +        int32_t(in0.real() >> 4) & 0xfff, +        int32_t(in1.real() >> 4) & 0xfff, +        int32_t(in2.real() >> 4) & 0xfff, +        int32_t(in3.real() >> 4) & 0xfff, +    }; -    const item32_t line0 = (i0 << 20) | (q0 << 8) | (i1 >> 4); -    const item32_t line1 = (i1 << 28) | (q1 << 16) | (i2 << 4) | (q2 >> 8); -    const item32_t line2 = (q2 << 24) | (i3 << 12) | (q3); +    int32_t q[4] { +        int32_t(in0.imag() >> 4) & 0xfff, +        int32_t(in1.imag() >> 4) & 0xfff, +        int32_t(in2.imag() >> 4) & 0xfff, +        int32_t(in3.imag() >> 4) & 0xfff, +    }; -    if (enable & CONVERT12_LINE0) -        output.line0 = towire(line0); -    if (enable & CONVERT12_LINE1) -        output.line1 = towire(line1); -    if (enable & CONVERT12_LINE2) -        output.line2 = towire(line2); +    pack<towire>(output, enable, i, q);  }  template <typename type, towire32_type towire> @@ -192,6 +228,16 @@ static converter::sptr make_convert_fc32_1_to_sc12_item32_be_1(void)      return converter::sptr(new convert_star_1_to_sc12_item32_1<float, uhd::ntohx>());  } +static converter::sptr make_convert_sc16_1_to_sc12_item32_le_1(void) +{ +    return converter::sptr(new convert_star_1_to_sc12_item32_1<short, uhd::wtohx>()); +} + +static converter::sptr make_convert_sc16_1_to_sc12_item32_be_1(void) +{ +    return converter::sptr(new convert_star_1_to_sc12_item32_1<short, uhd::ntohx>()); +} +  UHD_STATIC_BLOCK(register_convert_pack_sc12)  {      //uhd::convert::register_bytes_per_item("sc12", 3/*bytes*/); //registered in unpack @@ -199,11 +245,16 @@ UHD_STATIC_BLOCK(register_convert_pack_sc12)      uhd::convert::id_type id;      id.num_inputs = 1;      id.num_outputs = 1; -    id.input_format = "fc32"; +    id.input_format = "fc32";      id.output_format = "sc12_item32_le";      uhd::convert::register_converter(id, &make_convert_fc32_1_to_sc12_item32_le_1, PRIORITY_GENERAL); -      id.output_format = "sc12_item32_be";      uhd::convert::register_converter(id, &make_convert_fc32_1_to_sc12_item32_be_1, PRIORITY_GENERAL); + +    id.input_format = "sc16"; +    id.output_format = "sc12_item32_le"; +    uhd::convert::register_converter(id, &make_convert_sc16_1_to_sc12_item32_le_1, PRIORITY_GENERAL); +    id.output_format = "sc12_item32_be"; +    uhd::convert::register_converter(id, &make_convert_sc16_1_to_sc12_item32_be_1, PRIORITY_GENERAL);  } diff --git a/host/lib/convert/convert_unpack_sc12.cpp b/host/lib/convert/convert_unpack_sc12.cpp index f42e51c00..07f9cffa0 100644 --- a/host/lib/convert/convert_unpack_sc12.cpp +++ b/host/lib/convert/convert_unpack_sc12.cpp @@ -20,6 +20,7 @@  #include <uhd/utils/log.hpp>  #include <boost/math/special_functions/round.hpp>  #include <vector> +#include <type_traits>  using namespace uhd::convert; @@ -56,7 +57,8 @@ void convert_sc12_item32_3_to_star_4      std::complex<type> &out1,      std::complex<type> &out2,      std::complex<type> &out3, -    const double scalar +    const double scalar, +    typename std::enable_if<std::is_floating_point<type>::value>::type* = NULL  )  {      //step 0: extract the lines from the input buffer @@ -87,6 +89,32 @@ void convert_sc12_item32_3_to_star_4  }  template <typename type, tohost32_type tohost> +void convert_sc12_item32_3_to_star_4 +( +    const item32_sc12_3x &input, +    std::complex<type> &out0, +    std::complex<type> &out1, +    std::complex<type> &out2, +    std::complex<type> &out3, +    const double, +    typename std::enable_if<std::is_integral<type>::value>::type* = NULL +) +{ +    //step 0: extract the lines from the input buffer +    const item32_t line0 = tohost(input.line0); +    const item32_t line1 = tohost(input.line1); +    const item32_t line2 = tohost(input.line2); +    const uint64_t line01 = (uint64_t(line0) << 32) | line1; +    const uint64_t line12 = (uint64_t(line1) << 32) | line2; + +    //step 1: extract and load the outputs +    out0 = std::complex<type>(line0  >> 16 & 0xfff0, line0  >>  4 & 0xfff0); +    out1 = std::complex<type>(line01 >> 24 & 0xfff0, line1  >> 12 & 0xfff0); +    out2 = std::complex<type>(line1  >>  0 & 0xfff0, line12 >> 20 & 0xfff0); +    out3 = std::complex<type>(line2  >>  8 & 0xfff0, line2  <<  4 & 0xfff0); +} + +template <typename type, tohost32_type tohost>  struct convert_sc12_item32_1_to_star_1 : public converter  {      convert_sc12_item32_1_to_star_1(void):_scalar(0.0) @@ -193,18 +221,32 @@ static converter::sptr make_convert_sc12_item32_be_1_to_fc32_1(void)      return converter::sptr(new convert_sc12_item32_1_to_star_1<float, uhd::ntohx>());  } +static converter::sptr make_convert_sc12_item32_le_1_to_sc16_1(void) +{ +    return converter::sptr(new convert_sc12_item32_1_to_star_1<short, uhd::wtohx>()); +} + +static converter::sptr make_convert_sc12_item32_be_1_to_sc16_1(void) +{ +    return converter::sptr(new convert_sc12_item32_1_to_star_1<short, uhd::ntohx>()); +} +  UHD_STATIC_BLOCK(register_convert_unpack_sc12)  {      uhd::convert::register_bytes_per_item("sc12", 3/*bytes*/); -      uhd::convert::id_type id;      id.num_inputs = 1;      id.num_outputs = 1; -    id.output_format = "fc32"; +    id.output_format = "fc32";      id.input_format = "sc12_item32_le";      uhd::convert::register_converter(id, &make_convert_sc12_item32_le_1_to_fc32_1, PRIORITY_GENERAL); -      id.input_format = "sc12_item32_be";      uhd::convert::register_converter(id, &make_convert_sc12_item32_be_1_to_fc32_1, PRIORITY_GENERAL); + +    id.output_format = "sc16"; +    id.input_format = "sc12_item32_le"; +    uhd::convert::register_converter(id, &make_convert_sc12_item32_le_1_to_sc16_1, PRIORITY_GENERAL); +    id.input_format = "sc12_item32_be"; +    uhd::convert::register_converter(id, &make_convert_sc12_item32_be_1_to_sc16_1, PRIORITY_GENERAL);  } diff --git a/host/tests/convert_test.cpp b/host/tests/convert_test.cpp index af2828a17..982007d4e 100644 --- a/host/tests/convert_test.cpp +++ b/host/tests/convert_test.cpp @@ -70,13 +70,13 @@ template <typename Range> static void loopback(   * Test short conversion   **********************************************************************/  static void test_convert_types_sc16( -    size_t nsamps, convert::id_type &id, const int extra_div = 1 +    size_t nsamps, convert::id_type &id, const int extra_div = 1, int mask = 0xffff  ){      //fill the input samples      std::vector<sc16_t> input(nsamps), output(nsamps);      for(sc16_t &in:  input) in = sc16_t( -        short((float((std::rand())/(double(RAND_MAX)/2)) - 1)*32767/extra_div), -        short((float((std::rand())/(double(RAND_MAX)/2)) - 1)*32767/extra_div) +        short((float((std::rand())/(double(RAND_MAX)/2)) - 1)*32767/extra_div) & mask, +        short((float((std::rand())/(double(RAND_MAX)/2)) - 1)*32767/extra_div) & mask      );      //run the loopback and test @@ -235,6 +235,31 @@ BOOST_AUTO_TEST_CASE(test_convert_types_be_sc12_with_fc32){      }  } +BOOST_AUTO_TEST_CASE(test_convert_types_le_sc16_and_sc12){ +    convert::id_type id; +    id.input_format = "sc16"; +    id.num_inputs = 1; +    id.num_outputs = 1; + +    //try various lengths to test edge cases +    id.output_format = "sc12_item32_le"; +    for (size_t nsamps = 1; nsamps < 16; nsamps++){ +        test_convert_types_sc16(nsamps, id, 1, 0xfff0); +    } +} + +BOOST_AUTO_TEST_CASE(test_convert_types_be_sc16_and_sc12){ +    convert::id_type id; +    id.input_format = "sc16"; +    id.num_inputs = 1; +    id.num_outputs = 1; + +    id.output_format = "sc12_item32_be"; +    for (size_t nsamps = 1; nsamps < 16; nsamps++){ +        test_convert_types_sc16(nsamps, id, 1, 0xfff0); +    } +} +  /***********************************************************************   * Test float to/from fc32 conversion loopback   **********************************************************************/ diff --git a/host/utils/converter_benchmark.cpp b/host/utils/converter_benchmark.cpp index 0f0c72370..ba521441f 100644 --- a/host/utils/converter_benchmark.cpp +++ b/host/utils/converter_benchmark.cpp @@ -98,6 +98,28 @@ void init_random_vector_complex_int(std::vector<char> &buf_ptr, const size_t n_i      }  } +struct item32_sc12_3x +{ +    uint32_t line0; +    uint32_t line1; +    uint32_t line2; +}; + +template <typename T> +void init_random_vector_complex_sc12(std::vector<char> &buf_ptr, const size_t n_items) +{ +    item32_sc12_3x *const buf = reinterpret_cast<item32_sc12_3x * const>(&buf_ptr[0]); +    if (n_items % 4) throw std::invalid_argument(""); + +    for (size_t i = 0; i < n_items / 4; i++) { +        int16_t iq[8]; +        for (auto &k : iq) k = rand() & 0xfff; +        buf[i].line0 = iq[0] << 20 | iq[1] <<  8 | iq[2] >> 4; +        buf[i].line1 = iq[2] << 28 | iq[3] << 16 | iq[4] << 4 | iq[5] >> 8; +        buf[i].line2 = iq[5] << 24 | iq[6] << 12 | iq[7] << 0; +    } +} +  template <typename T>  void init_random_vector_real_int(std::vector<char> &buf_ptr, size_t n_items)  { @@ -164,6 +186,8 @@ void init_buffers(      for (size_t i = 0; i < buf.size(); i++) {          if (type == "sc8") {              init_random_vector_complex_int<int8_t>(buf[i], n_items); +        } else if (type == "sc12") { +            init_random_vector_complex_sc12<int16_t>(buf[i], n_items);          } else if (type == "sc16") {              init_random_vector_complex_int<int16_t>(buf[i], n_items);          } else if (type == "sc32") { | 
