diff options
author | Martin Braun <martin.braun@ettus.com> | 2015-09-01 16:00:31 -0700 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2015-09-01 16:00:31 -0700 |
commit | 71f6902d33f5c915bf15409428654ebfe7314226 (patch) | |
tree | 5afb9d6bfe517a951970c866da5f0bc857e073bd /host | |
parent | 6464a000150858b5d65a53490f0593d5ba1e4ca6 (diff) | |
download | uhd-71f6902d33f5c915bf15409428654ebfe7314226.tar.gz uhd-71f6902d33f5c915bf15409428654ebfe7314226.tar.bz2 uhd-71f6902d33f5c915bf15409428654ebfe7314226.zip |
convert: Added s8, s16 types and did some refactoring
Diffstat (limited to 'host')
-rw-r--r-- | host/lib/convert/convert_item32.cpp | 3 | ||||
-rw-r--r-- | host/lib/convert/gen_convert_general.py | 132 | ||||
-rw-r--r-- | host/tests/convert_test.cpp | 163 |
3 files changed, 265 insertions, 33 deletions
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..ac8d7c7bd 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,44 @@ 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) {{ + const s16_t *last_input_word = reinterpret_cast<const s16_t *>(&input[n_words]); + s16_t *last_output_word = reinterpret_cast<s16_t *>(&output[n_words]); + last_output_word[0] = last_input_word[0]; + output[n_words] = {to_wire}(output[n_words]); + }} +}} + +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 last_input_word = {to_host}(input[n_words]); + const s16_t *last_input_word_ptr = reinterpret_cast<const s16_t *>(&last_input_word); + s16_t *last_output_word = reinterpret_cast<s16_t *>(&output[n_words]); + last_output_word[0] = last_input_word_ptr[0]; + }} +}} +""" + TMPL_CONV_USRP1_COMPLEX = """ DECLARE_CONVERTER(${cpu_type}, ${width}, sc16_item16_usrp1, 1, PRIORITY_GENERAL){ % for w in range(width): @@ -164,23 +209,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/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); + } +} |