#!/usr/bin/env python # # Copyright 2011-2012 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 . # TMPL_HEADER = """ <% import time %> /*********************************************************************** * This file was generated by ${file} on ${time.strftime("%c")} **********************************************************************/ #include "convert_common.hpp" #include using namespace uhd::convert; // item32 -> item32: Just a memcpy. No scaling possible. DECLARE_CONVERTER(item32, 1, item32, 1, PRIORITY_GENERAL) { const item32_t *input = reinterpret_cast(inputs[0]); item32_t *output = reinterpret_cast(outputs[0]); memcpy(output, input, nsamps * sizeof(item32_t)); } """ # 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(inputs[0]); item32_t *output = reinterpret_cast(outputs[0]); for (size_t i = 0; i < nsamps; i++) {{ output[i] = {to_wire_or_host}(input[i]); }} }} """ # 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(inputs[0]); item32_t *output = reinterpret_cast(outputs[0]); // 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_U8S8 = """ DECLARE_CONVERTER({us8}, 1, {us8}_item32_{end}, 1, PRIORITY_GENERAL) {{ const item32_t *input = reinterpret_cast(inputs[0]); item32_t *output = reinterpret_cast(outputs[0]); // 1) Copy all the 4-byte tuples size_t n_words = nsamps / 4; for (size_t i = 0; i < n_words; i++) {{ output[i] = {to_wire}(input[i]); }} // 2) If nsamps was not a multiple of 4, copy the rest by hand size_t bytes_left = nsamps % 4; if (bytes_left) {{ const {us8}_t *last_input_word = reinterpret_cast(&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]; }} output[n_words] = {to_wire}(output[n_words]); }} }} DECLARE_CONVERTER({us8}_item32_{end}, 1, {us8}, 1, PRIORITY_GENERAL) {{ const item32_t *input = reinterpret_cast(inputs[0]); item32_t *output = reinterpret_cast(outputs[0]); // 1) Copy all the 4-byte tuples size_t n_words = nsamps / 4; for (size_t i = 0; i < n_words; i++) {{ output[i] = {to_host}(input[i]); }} // 2) If nsamps was not a multiple of 4, copy the rest by hand size_t bytes_left = nsamps % 4; if (bytes_left) {{ item32_t last_input_word = {to_host}(input[n_words]); const {us8}_t *last_input_word_ptr = reinterpret_cast(&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]; }} }} }} """ TMPL_CONV_S16 = """ DECLARE_CONVERTER(s16, 1, s16_item32_{end}, 1, PRIORITY_GENERAL) {{ const item32_t *input = reinterpret_cast(inputs[0]); item32_t *output = reinterpret_cast(outputs[0]); // 1) Copy all the 4-byte tuples size_t n_words = nsamps / 2; for (size_t i = 0; i < n_words; i++) {{ output[i] = {to_wire}(input[i]); }} // 2) If nsamps was not a multiple of 2, copy the last one by hand if (nsamps % 2) {{ item32_t tmp = item32_t(*reinterpret_cast(&input[n_words])); output[n_words] = {to_wire}(tmp); }} }} DECLARE_CONVERTER(s16_item32_{end}, 1, s16, 1, PRIORITY_GENERAL) {{ const item32_t *input = reinterpret_cast(inputs[0]); item32_t *output = reinterpret_cast(outputs[0]); // 1) Copy all the 4-byte tuples size_t n_words = nsamps / 2; for (size_t i = 0; i < n_words; i++) {{ output[i] = {to_host}(input[i]); }} // 2) If nsamps was not a multiple of 2, copy the last one by hand if (nsamps % 2) {{ item32_t tmp = {to_host}(input[n_words]); *reinterpret_cast(&output[n_words]) = s16_t(tmp); }} }} """ TMPL_CONV_USRP1_COMPLEX = """ DECLARE_CONVERTER(${cpu_type}, ${width}, sc16_item16_usrp1, 1, PRIORITY_GENERAL){ % for w in range(width): const ${cpu_type}_t *input${w} = reinterpret_cast(inputs[${w}]); % endfor uint16_t *output = reinterpret_cast(outputs[0]); for (size_t i = 0, j = 0; i < nsamps; i++){ % for w in range(width): output[j++] = ${to_wire}(uint16_t(int16_t(input${w}[i].real()${do_scale}))); output[j++] = ${to_wire}(uint16_t(int16_t(input${w}[i].imag()${do_scale}))); % endfor } } DECLARE_CONVERTER(sc16_item16_usrp1, 1, ${cpu_type}, ${width}, PRIORITY_GENERAL){ const uint16_t *input = reinterpret_cast(inputs[0]); % for w in range(width): ${cpu_type}_t *output${w} = reinterpret_cast<${cpu_type}_t *>(outputs[${w}]); % endfor for (size_t i = 0, j = 0; i < nsamps; i++){ % for w in range(width): output${w}[i] = ${cpu_type}_t( int16_t(${to_host}(input[j+0]))${do_scale}, int16_t(${to_host}(input[j+1]))${do_scale} ); j += 2; % endfor } } DECLARE_CONVERTER(sc8_item16_usrp1, 1, ${cpu_type}, ${width}, PRIORITY_GENERAL){ const uint16_t *input = reinterpret_cast(inputs[0]); % for w in range(width): ${cpu_type}_t *output${w} = reinterpret_cast<${cpu_type}_t *>(outputs[${w}]); % endfor for (size_t i = 0, j = 0; i < nsamps; i++){ % for w in range(width): { const uint16_t num = ${to_host}(input[j++]); output${w}[i] = ${cpu_type}_t( int8_t(num)${do_scale}, int8_t(num >> 8)${do_scale} ); } % endfor } } """ def parse_tmpl(_tmpl_text, **kwargs): from mako.template import Template return Template(_tmpl_text).render(**kwargs) if __name__ == '__main__': import sys, os file = os.path.basename(__file__) output = parse_tmpl(TMPL_HEADER, file=file) ## 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_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 ( ('fc64', '*scale_factor'), ('fc32', '*float(scale_factor)'), ('sc16', ''), ): output += parse_tmpl( TMPL_CONV_USRP1_COMPLEX, width=width, to_host='uhd::wtohx', to_wire='uhd::htowx', cpu_type=cpu_type, do_scale=do_scale ) open(sys.argv[1], 'w').write(output)