diff options
author | Martin Braun <martin.braun@kit.edu> | 2013-03-15 02:12:20 -0700 |
---|---|---|
committer | Tom Rondeau <trondeau@vt.edu> | 2013-03-16 23:52:19 -0400 |
commit | 7fd15b67afa5abd20c0982bdd6bcb7191831bf73 (patch) | |
tree | 3bd525f2850e662a9ccfe0a6c286ff7c20ad57e3 /gr-digital/lib | |
parent | 34216336205ba3edc0bc308a8da9ad388f3d0774 (diff) |
Squash/rebased martin/ofdm-master onto trial merge branch
Conflicts:
gr-blocks/include/blocks/CMakeLists.txt
Diffstat (limited to 'gr-digital/lib')
27 files changed, 2903 insertions, 21 deletions
diff --git a/gr-digital/lib/CMakeLists.txt b/gr-digital/lib/CMakeLists.txt index bc0e925dea..d1193f8fed 100644 --- a/gr-digital/lib/CMakeLists.txt +++ b/gr-digital/lib/CMakeLists.txt @@ -24,6 +24,8 @@ include_directories( ${CMAKE_CURRENT_BINARY_DIR}/../include ${GR_DIGITAL_INCLUDE_DIRS} ${GR_ANALOG_INCLUDE_DIRS} + ${GR_FILTER_INCLUDE_DIRS} + ${GR_BLOCKS_INCLUDE_DIRS} ${GNURADIO_CORE_INCLUDE_DIRS} ${GRUEL_INCLUDE_DIRS} ${LOG4CPP_INCLUDE_DIRS} @@ -139,6 +141,23 @@ list(APPEND gr_digital_sources digital_probe_mpsk_snr_est_c.cc digital_scrambler_bb.cc digital_simple_framer.cc + digital_ofdm_sync_sc_cfb.cc + digital_ofdm_chanest_vcvc.cc + digital_crc32_bb.cc + digital_ofdm_carrier_allocator_cvc.cc + digital_ofdm_equalizer_base.cc + digital_ofdm_equalizer_static.cc + digital_ofdm_equalizer_simpledfe.cc + ofdm_frame_equalizer_vcvc_impl.cc + ofdm_serializer_vcc_impl.cc + packet_header_default.cc + packet_header_ofdm.cc + packet_headergenerator_bb_impl.cc + packet_headerparser_b_impl.cc + scale_tags_impl.cc + tagged_stream_check_impl.cc + ts_insert_zeros_cc_impl.cc + header_payload_demux_impl.cc digital_simple_correlator.cc ) @@ -158,6 +177,9 @@ ENDIF(MSVC) list(APPEND digital_libs gnuradio-core + gnuradio-blocks + gnuradio-analog + gnuradio-filter ${Boost_LIBRARIES} ${LOG4CPP_LIBRARIES} ) @@ -165,5 +187,11 @@ list(APPEND digital_libs add_library(gnuradio-digital SHARED ${gr_digital_sources}) target_link_libraries(gnuradio-digital ${digital_libs}) GR_LIBRARY_FOO(gnuradio-digital RUNTIME_COMPONENT "digital_runtime" DEVEL_COMPONENT "digital_devel") +add_dependencies(gnuradio-digital + digital_generated_includes + digital_generated_swigs + gnuradio-analog + gnuradio-blocks + gnuradio-filter +) -add_dependencies(gnuradio-digital digital_generated_includes digital_generated_swigs gnuradio-analog) diff --git a/gr-digital/lib/digital_crc32_bb.cc b/gr-digital/lib/digital_crc32_bb.cc new file mode 100644 index 0000000000..89d9e42151 --- /dev/null +++ b/gr-digital/lib/digital_crc32_bb.cc @@ -0,0 +1,102 @@ +/* -*- c++ -*- */ +/* Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gr_io_signature.h> +#include <digital_crc32.h> +#include "digital_crc32_bb.h" + +digital_crc32_bb_sptr +digital_make_crc32_bb (bool check, const std::string& lengthtagname) +{ + return gnuradio::get_initial_sptr (new digital_crc32_bb(check, lengthtagname)); +} + + +digital_crc32_bb::digital_crc32_bb (bool check, const std::string& lengthtagname) + : gr_tagged_stream_block ("crc32_bb", + gr_make_io_signature(1, 1, sizeof (char)), + gr_make_io_signature(1, 1, sizeof (char)), + lengthtagname), + d_check(check) +{ + set_tag_propagation_policy(TPP_DONT); +} + + +digital_crc32_bb::~digital_crc32_bb() +{ +} + + +int +digital_crc32_bb::calculate_output_stream_length(const std::vector<int> &ninput_items) +{ + if (d_check) { + return ninput_items[0] - 4; + } else { + return ninput_items[0] + 4; + } +} + + +int +digital_crc32_bb::work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + const unsigned char *in = (const unsigned char *) input_items[0]; + unsigned char *out = (unsigned char *) output_items[0]; + long packet_length = ninput_items[0]; + int packet_size_diff = d_check ? -4 : 4; + unsigned int crc; + + if (d_check) { + crc = digital_crc32(in, packet_length-4); + if (crc != *(unsigned int *)(in+packet_length-4)) { // Drop package + return 0; + } + memcpy((void *) out, (const void *) in, packet_length-4); + } else { + crc = digital_crc32(in, packet_length); + memcpy((void *) out, (const void *) in, packet_length); + memcpy((void *) (out + packet_length), &crc, 4); // FIXME big-endian/little-endian, this might be wrong + } + + std::vector<gr_tag_t> tags; + get_tags_in_range(tags, 0, nitems_read(0), nitems_read(0)+packet_length); + for (unsigned i = 0; i < tags.size(); i++) { + tags[i].offset -= nitems_read(0); + if (d_check && tags[i].offset > packet_length+packet_size_diff) { + tags[i].offset = packet_length-5; + } + add_item_tag(0, nitems_written(0) + tags[i].offset, + tags[i].key, + tags[i].value); + } + + return packet_length + packet_size_diff; +} + diff --git a/gr-digital/lib/digital_ofdm_carrier_allocator_cvc.cc b/gr-digital/lib/digital_ofdm_carrier_allocator_cvc.cc new file mode 100644 index 0000000000..e5b3013302 --- /dev/null +++ b/gr-digital/lib/digital_ofdm_carrier_allocator_cvc.cc @@ -0,0 +1,156 @@ +/* -*- c++ -*- */ +/* Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gr_io_signature.h> +#include "digital_ofdm_carrier_allocator_cvc.h" + +digital_ofdm_carrier_allocator_cvc_sptr +digital_make_ofdm_carrier_allocator_cvc ( + int fft_len, + const std::vector<std::vector<int> > &occupied_carriers, + const std::vector<std::vector<int> > &pilot_carriers, + const std::vector<std::vector<gr_complex> > &pilot_symbols, + const std::string &len_tag_key) +{ + return gnuradio::get_initial_sptr (new digital_ofdm_carrier_allocator_cvc(fft_len, occupied_carriers, pilot_carriers, pilot_symbols, len_tag_key)); +} + + +digital_ofdm_carrier_allocator_cvc::digital_ofdm_carrier_allocator_cvc ( + int fft_len, + const std::vector<std::vector<int> > &occupied_carriers, + const std::vector<std::vector<int> > &pilot_carriers, + const std::vector<std::vector<gr_complex> > &pilot_symbols, + const std::string &len_tag_key) + : gr_tagged_stream_block ("ofdm_carrier_allocator_cvc", + gr_make_io_signature(1, 1, sizeof (gr_complex)), + gr_make_io_signature(1, 1, sizeof (gr_complex) * fft_len), len_tag_key), + d_fft_len(fft_len), + d_occupied_carriers(occupied_carriers), + d_pilot_carriers(pilot_carriers), + d_pilot_symbols(pilot_symbols), + d_symbols_per_set(0) +{ + for (unsigned i = 0; i < d_occupied_carriers.size(); i++) { + for (unsigned j = 0; j < d_occupied_carriers[i].size(); j++) { + if (occupied_carriers[i][j] < 0) { + d_occupied_carriers[i][j] += d_fft_len; + } + if (d_occupied_carriers[i][j] > d_fft_len || d_occupied_carriers[i][j] < 0) { + throw std::invalid_argument("data carrier index out of bounds"); + } + } + } + for (unsigned i = 0; i < d_pilot_carriers.size(); i++) { + if (d_pilot_carriers[i].size() != pilot_symbols[i].size()) { + throw std::invalid_argument("pilot_carriers do not match pilot_symbols"); + } + for (unsigned j = 0; j < d_pilot_carriers[i].size(); j++) { + if (d_pilot_carriers[i][j] < 0) { + d_pilot_carriers[i][j] += d_fft_len; + } + if (d_pilot_carriers[i][j] > d_fft_len || d_pilot_carriers[i][j] < 0) { + throw std::invalid_argument("pilot carrier index out of bounds"); + } + } + } + + for (unsigned i = 0; i < d_occupied_carriers.size(); i++) { + d_symbols_per_set += d_occupied_carriers[i].size(); + } + set_tag_propagation_policy(TPP_DONT); + set_relative_rate((double) d_symbols_per_set / d_occupied_carriers.size()); +} + + +digital_ofdm_carrier_allocator_cvc::~digital_ofdm_carrier_allocator_cvc() +{ +} + + +int +digital_ofdm_carrier_allocator_cvc::calculate_output_stream_length(const gr_vector_int &ninput_items) +{ + int nin = ninput_items[0]; + int nout = (nin / d_symbols_per_set) * d_occupied_carriers.size(); + int k = 0; + for (int i = 0; i < nin % d_symbols_per_set; k++) { + nout++; + i += d_occupied_carriers[k % d_occupied_carriers.size()].size(); + } + return nout; +} + + +int +digital_ofdm_carrier_allocator_cvc::work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + const gr_complex *in = (const gr_complex *) input_items[0]; + gr_complex *out = (gr_complex *) output_items[0]; + + std::vector<gr_tag_t> tags; + + memset((void *) out, 0x00, sizeof(gr_complex) * d_fft_len * noutput_items); + long n_ofdm_symbols = 0; + int curr_set = 0; + int symbols_to_allocate = d_occupied_carriers[0].size(); + int symbols_allocated = 0; + for (int i = 0; i < ninput_items[0]; i++) { + if (symbols_allocated == 0) { + // Copy all tags associated with these input symbols onto this OFDM symbol + get_tags_in_range(tags, 0, + nitems_read(0)+i, + nitems_read(0)+std::min(i+symbols_to_allocate, (int) ninput_items[0]) + ); + for (unsigned t = 0; t < tags.size(); t++) { + add_item_tag(0, nitems_written(0)+n_ofdm_symbols, + tags[t].key, + tags[t].value); + } + n_ofdm_symbols++; + } + out[(n_ofdm_symbols-1) * d_fft_len + d_occupied_carriers[curr_set][symbols_allocated]] = in[i]; + symbols_allocated++; + if (symbols_allocated == symbols_to_allocate) { + curr_set = (curr_set + 1) % d_occupied_carriers.size(); + symbols_to_allocate = d_occupied_carriers[curr_set].size(); + symbols_allocated = 0; + } + } + // 2) Copy pilot symbols + curr_set = 0; + for (int i = 0; i < n_ofdm_symbols; i++) { + for (unsigned k = 0; k < d_pilot_carriers[curr_set].size(); k++) { + out[i * d_fft_len + d_pilot_carriers[curr_set][k]] = d_pilot_symbols[curr_set][k]; + } + curr_set = (curr_set + 1) % d_pilot_carriers.size(); + } + + return n_ofdm_symbols; +} + diff --git a/gr-digital/lib/digital_ofdm_chanest_vcvc.cc b/gr-digital/lib/digital_ofdm_chanest_vcvc.cc new file mode 100644 index 0000000000..f38017e00b --- /dev/null +++ b/gr-digital/lib/digital_ofdm_chanest_vcvc.cc @@ -0,0 +1,281 @@ +/* -*- c++ -*- */ +// vim: set sw=2: +/* Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gr_io_signature.h> +#include "digital_ofdm_chanest_vcvc.h" + +digital_ofdm_chanest_vcvc_sptr +digital_make_ofdm_chanest_vcvc ( + const std::vector<gr_complex> &sync_symbol1, + const std::vector<gr_complex> &sync_symbol2, + int n_data_symbols, + int eq_noise_red_len, + int max_carr_offset, + bool force_one_sync_symbol) +{ + return gnuradio::get_initial_sptr (new digital_ofdm_chanest_vcvc( + sync_symbol1, sync_symbol2, n_data_symbols, eq_noise_red_len, max_carr_offset, force_one_sync_symbol)); +} + + +digital_ofdm_chanest_vcvc::digital_ofdm_chanest_vcvc ( + const std::vector<gr_complex> &sync_symbol1, + const std::vector<gr_complex> &sync_symbol2, + int n_data_symbols, + int eq_noise_red_len, + int max_carr_offset, + bool force_one_sync_symbol) + : gr_block ("ofdm_chanest_vcvc", + gr_make_io_signature(1, 1, sizeof (gr_complex) * sync_symbol1.size()), + gr_make_io_signature(1, 1, sizeof (gr_complex) * sync_symbol1.size())), + d_fft_len(sync_symbol1.size()), + d_n_data_syms(n_data_symbols), + d_n_sync_syms(1), + d_eq_noise_red_len(eq_noise_red_len), + d_ref_sym((sync_symbol2.size() && !force_one_sync_symbol) ? sync_symbol2 : sync_symbol1), + d_corr_v(sync_symbol2), + d_known_symbol_diffs(0, 0), + d_new_symbol_diffs(0, 0), + d_interpolate(false) +{ + // Set index of first and last active carrier + for (int i = 0; i < d_fft_len; i++) { + if (d_ref_sym[i] != gr_complex(0, 0)) { + d_first_active_carrier = i; + break; + } + } + for (int i = d_fft_len-1; i >= 0; i--) { + if (d_ref_sym[i] != gr_complex(0, 0)) { + d_last_active_carrier = i; + break; + } + } + + // Sanity checks + if (sync_symbol2.size()) { + if (sync_symbol1.size() != sync_symbol2.size()) { + throw std::invalid_argument("sync symbols must have equal length."); + } + if (!force_one_sync_symbol) { + d_n_sync_syms = 2; + } + } else { + if (sync_symbol1[d_first_active_carrier+1] == gr_complex(0, 0)) { + d_last_active_carrier++; + d_interpolate = true; + } + } + + // Set up coarse freq estimation info + // Allow all possible values: + d_max_neg_carr_offset = -d_first_active_carrier; + d_max_pos_carr_offset = d_fft_len - d_last_active_carrier - 1; + if (max_carr_offset != -1) { + d_max_neg_carr_offset = std::max(-max_carr_offset, d_max_neg_carr_offset); + d_max_pos_carr_offset = std::min(max_carr_offset, d_max_pos_carr_offset); + } + // Carrier offsets must be even + if (d_max_neg_carr_offset % 2) + d_max_neg_carr_offset++; + if (d_max_pos_carr_offset % 2) + d_max_pos_carr_offset--; + + if (d_n_sync_syms == 2) { + for (int i = 0; i < d_fft_len; i++) { + if (sync_symbol1[i] == gr_complex(0, 0)) { + d_corr_v[i] = gr_complex(0, 0); + } else { + d_corr_v[i] /= sync_symbol1[i]; + } + } + } else { + d_corr_v.resize(0, 0); + d_known_symbol_diffs.resize(d_fft_len, 0); + d_new_symbol_diffs.resize(d_fft_len, 0); + for (int i = d_first_active_carrier; i < d_last_active_carrier-2 && i < d_fft_len-2; i += 2) { + d_known_symbol_diffs[i] = std::norm(sync_symbol1[i] - sync_symbol1[i+2]); + } + } + + set_relative_rate((double) n_data_symbols / (n_data_symbols + d_n_sync_syms)); + set_tag_propagation_policy(TPP_DONT); +} + + +digital_ofdm_chanest_vcvc::~digital_ofdm_chanest_vcvc() +{ +} + +void +digital_ofdm_chanest_vcvc::forecast (int noutput_items, gr_vector_int &ninput_items_required) +{ + ninput_items_required[0] = (noutput_items/d_n_data_syms) * (d_n_data_syms + d_n_sync_syms); +} + + +int +digital_ofdm_chanest_vcvc::get_carr_offset(const gr_complex *sync_sym1, const gr_complex *sync_sym2) +{ + int carr_offset = 0; + if (d_corr_v.size()) { + // Use Schmidl & Cox method + float Bg_max = 0; + // g here is 2g in the paper + for (int g = d_max_neg_carr_offset; g <= d_max_pos_carr_offset; g += 2) { + gr_complex tmp = gr_complex(0, 0); + for (int k = 0; k < d_fft_len; k++) { + if (d_corr_v[k] != gr_complex(0, 0)) { + tmp += std::conj(sync_sym1[k+g]) * std::conj(d_corr_v[k]) * sync_sym2[k+g]; + } + } + if (std::abs(tmp) > Bg_max) { + Bg_max = std::abs(tmp); + carr_offset = g; + } + } + } else { + // Correlate + std::fill(d_new_symbol_diffs.begin(), d_new_symbol_diffs.end(), 0); + for(int i = 0; i < d_fft_len-2; i++) { + d_new_symbol_diffs[i] = std::norm(sync_sym1[i] - sync_sym1[i+2]); + } + + float sum; + float max = 0; + for (int g = d_max_neg_carr_offset; g <= d_max_pos_carr_offset; g += 2) { + sum = 0; + for (int j = 0; j < d_fft_len; j++) { + if (d_known_symbol_diffs[j]) { + sum += (d_known_symbol_diffs[j] * d_new_symbol_diffs[j + g]); + } + if(sum > max) { + max = sum; + carr_offset = g; + } + } + } + } + return carr_offset; +} + + +void +digital_ofdm_chanest_vcvc::get_chan_taps( + const gr_complex *sync_sym1, + const gr_complex *sync_sym2, + int carr_offset, + std::vector<gr_complex> &taps) +{ + const gr_complex *sym = ((d_n_sync_syms == 2) ? sync_sym2 : sync_sym1); + std::fill(taps.begin(), taps.end(), gr_complex(0, 0)); + int loop_start = 0; + int loop_end = d_fft_len; + if (carr_offset > 0) { + loop_start = carr_offset; + } else if (carr_offset < 0) { + loop_end = d_fft_len + carr_offset; + } + for (int i = loop_start; i < loop_end; i++) { + if ((d_ref_sym[i-carr_offset] != gr_complex(0, 0))) { + taps[i] = sym[i] / d_ref_sym[i-carr_offset]; + } + } + + if (d_interpolate) { + for (int i = d_first_active_carrier + 1; i < d_last_active_carrier; i += 2) { + taps[i] = (taps[i-1] + taps[i+1]) / gr_complex(2.0, 0); + } + taps[d_last_active_carrier] = taps[d_last_active_carrier-1]; + } + + if (d_eq_noise_red_len) { + // TODO + // 1) IFFT + // 2) Set all elements > d_eq_noise_red_len to zero + // 3) FFT + } +} + + +// 1) Go through all the frames available on the input buffer +// 2) Estimate the coarse freq. offset and the eq. taps from the +// input symbol(s) +// 3) Copy the data symbols to the output +// 4) Copy all other tags onto the output. A tag that was on +// a sync symbol is copied onto the first data symbol. +// 5) Add the new tags for carrier offset and eq. taps +int +digital_ofdm_chanest_vcvc::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + const gr_complex *in = (const gr_complex *) input_items[0]; + gr_complex *out = (gr_complex *) output_items[0]; + int n_frames = noutput_items/d_n_data_syms; + const int framesize = d_n_sync_syms + d_n_data_syms; + + for (int i = 0; i < n_frames; i++) { + int carr_offset = 0; + if (d_max_neg_carr_offset || d_max_pos_carr_offset) + carr_offset = get_carr_offset(in, in+d_fft_len); + std::vector<gr_complex> chan_taps(d_fft_len, 0); + get_chan_taps(in, in+d_fft_len, carr_offset, chan_taps); + + memcpy((void *) out, + (void *) &in[d_n_sync_syms * d_fft_len], + sizeof(gr_complex) * d_fft_len * d_n_data_syms); + in += framesize * d_fft_len; + out += d_n_data_syms * d_fft_len; + + std::vector<gr_tag_t> tags; + this->get_tags_in_range(tags, 0, + this->nitems_read(0)+i*framesize, + this->nitems_read(0)+(i+1)*framesize); + for (unsigned t = 0; t < tags.size(); t++) { + int offset = tags[t].offset - (this->nitems_read(0) + i*framesize); + if (offset < d_n_sync_syms) { + offset = 0; + } else { + offset -= d_n_sync_syms; + } + tags[t].offset = offset + this->nitems_written(0) + i*d_n_data_syms; + this->add_item_tag(0, tags[t]); + } + + this->add_item_tag(0, this->nitems_written(0) + i*d_n_data_syms, + pmt::pmt_string_to_symbol("ofdm_sync_carr_offset"), + pmt::pmt_from_long(carr_offset)); + this->add_item_tag(0, this->nitems_written(0) + i*d_n_data_syms, + pmt::pmt_string_to_symbol("ofdm_sync_chan_taps"), + pmt::pmt_init_c32vector(d_fft_len, chan_taps)); + } + + consume_each(n_frames * framesize); + return n_frames * d_n_data_syms; +} + diff --git a/gr-digital/lib/digital_ofdm_cyclic_prefixer.cc b/gr-digital/lib/digital_ofdm_cyclic_prefixer.cc index 192af2591d..ada5742a51 100644 --- a/gr-digital/lib/digital_ofdm_cyclic_prefixer.cc +++ b/gr-digital/lib/digital_ofdm_cyclic_prefixer.cc @@ -24,47 +24,139 @@ #include "config.h" #endif +#include <cmath> #include <digital_ofdm_cyclic_prefixer.h> #include <gr_io_signature.h> digital_ofdm_cyclic_prefixer_sptr -digital_make_ofdm_cyclic_prefixer (size_t input_size, size_t output_size) +digital_make_ofdm_cyclic_prefixer (size_t input_size, + size_t output_size, + int rolloff_len, + const std::string &len_tag_key) { return gnuradio::get_initial_sptr(new digital_ofdm_cyclic_prefixer (input_size, - output_size)); + output_size, + rolloff_len, + len_tag_key)); } digital_ofdm_cyclic_prefixer::digital_ofdm_cyclic_prefixer (size_t input_size, - size_t output_size) - : gr_sync_interpolator ("ofdm_cyclic_prefixer", - gr_make_io_signature (1, 1, input_size*sizeof(gr_complex)), - gr_make_io_signature (1, 1, sizeof(gr_complex)), - output_size), - d_input_size(input_size), - d_output_size(output_size) + size_t output_size, + int rolloff_len, + const std::string &len_tag_key) + : gr_tagged_stream_block ("ofdm_cyclic_prefixer", + gr_make_io_signature (1, 1, input_size*sizeof(gr_complex)), + gr_make_io_signature (1, 1, sizeof(gr_complex)), + len_tag_key), + d_fft_len(input_size), + d_output_size(output_size), + d_cp_size(output_size - input_size), + d_rolloff_len(rolloff_len), + d_up_flank((rolloff_len ? rolloff_len-1 : 0), 0), + d_down_flank((rolloff_len ? rolloff_len-1 : 0), 0), + d_delay_line(0, 0) +{ + set_relative_rate(d_output_size); + + // Flank of length 1 would just be rectangular + if (d_rolloff_len == 1) { + d_rolloff_len = 0; + } + if (d_rolloff_len) { + d_delay_line.resize(d_rolloff_len-1, 0); + if (rolloff_len > d_cp_size) { + throw std::invalid_argument("cyclic prefixer: rolloff len must smaller than the cyclic prefix."); + } + // The actual flanks are one sample shorter than d_rolloff_len, because the + // first sample of the up- and down flank is always zero and one, respectively + for (int i = 1; i < d_rolloff_len; i++) { + d_up_flank[i-1] = 0.5 * (1 + cos(M_PI * i/rolloff_len - M_PI)); + d_down_flank[i-1] = 0.5 * (1 + cos(M_PI * (rolloff_len-i)/rolloff_len - M_PI)); + } + } + if (len_tag_key.empty()) { + set_output_multiple(d_output_size); + } else { + set_tag_propagation_policy(TPP_DONT); + } +} + +int +digital_ofdm_cyclic_prefixer::calculate_output_stream_length(const gr_vector_int &ninput_items) { + int nout = ninput_items[0] * d_output_size + d_delay_line.size(); + return nout; } +// Operates in two ways: +// - When there's a length tag name specified, operates in packet mode. +// Here, an entire OFDM frame is processed at once. The final OFDM symbol +// is postfixed with the delay line of the pulse shape. +// We manually propagate tags. +// - Otherwise, we're in freewheeling mode. Process as many OFDM symbols as +// are space for in the output buffer. The delay line is never flushed. +// Tags are propagated by the scheduler. int digital_ofdm_cyclic_prefixer::work (int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) { gr_complex *in = (gr_complex *) input_items[0]; gr_complex *out = (gr_complex *) output_items[0]; - size_t cp_size = d_output_size - d_input_size; - unsigned int i=0, j=0; + int symbols_to_read = 0; - j = cp_size; - for(i=0; i < d_input_size; i++,j++) { - out[j] = in[i]; + // 1) Figure out if we're in freewheeling or packet mode + if (!d_length_tag_key_str.empty()) { + symbols_to_read = ninput_items[0]; + noutput_items = symbols_to_read * d_output_size + d_delay_line.size(); + } else { + symbols_to_read = std::min(noutput_items / (int) d_output_size, ninput_items[0]); + noutput_items = symbols_to_read * d_output_size; } - j = d_input_size - cp_size; - for(i=0; i < cp_size; i++, j++) { - out[i] = in[j]; + // 2) Do the cyclic prefixing and, optionally, the pulse shaping + for (int sym_idx = 0; sym_idx < symbols_to_read; sym_idx++) { + memcpy((void *)(out + d_cp_size), (void *) in, d_fft_len * sizeof(gr_complex)); + memcpy((void *) out, (void *) (in + d_fft_len - d_cp_size), d_cp_size * sizeof(gr_complex)); + if (d_rolloff_len) { + for (int i = 0; i < d_rolloff_len-1; i++) { + out[i] = out[i] * d_up_flank[i] + d_delay_line[i]; + d_delay_line[i] = in[i] * d_down_flank[i]; + } + } + in += d_fft_len; + out += d_output_size; } - return d_output_size; + // 3) If we're in packet mode: + // - flush the delay line, if applicable + // - Propagate tags + if (!d_length_tag_key_str.empty()) { + if (d_rolloff_len) { + for (unsigned i = 0; i < d_delay_line.size(); i++) { + *out++ = d_delay_line[i]; + } + d_delay_line.assign(d_delay_line.size(), 0); + } + std::vector<gr_tag_t> tags; + get_tags_in_range( + tags, 0, + nitems_read(0), nitems_read(0)+symbols_to_read + ); + for (unsigned i = 0; i < tags.size(); i++) { + tags[i].offset = ((tags[i].offset - nitems_read(0)) * d_output_size) + nitems_written(0); + add_item_tag(0, + tags[i].offset, + tags[i].key, + tags[i].value + ); + } + } else { + consume_each(symbols_to_read); + } + + return noutput_items; } + diff --git a/gr-digital/lib/digital_ofdm_equalizer_base.cc b/gr-digital/lib/digital_ofdm_equalizer_base.cc new file mode 100644 index 0000000000..b4fa5df87e --- /dev/null +++ b/gr-digital/lib/digital_ofdm_equalizer_base.cc @@ -0,0 +1,116 @@ +/* -*- c++ -*- */ +/* Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "digital_ofdm_equalizer_base.h" + +// *** Base class **************************************************** +digital_ofdm_equalizer_base::digital_ofdm_equalizer_base(int fft_len) : + d_fft_len(fft_len), + d_carr_offset(0) +{ +} + + +digital_ofdm_equalizer_base::~digital_ofdm_equalizer_base() +{ +} + + +// *** Sub-Base class for 1D equalizers using pilot tones ************* +digital_ofdm_equalizer_1d_pilots::digital_ofdm_equalizer_1d_pilots( + int fft_len, + const std::vector<std::vector<int> > &occupied_carriers, + const std::vector<std::vector<int> > &pilot_carriers, + const std::vector<std::vector<gr_complex> > &pilot_symbols, + int symbols_skipped, + bool input_is_shifted) + : digital_ofdm_equalizer_base(fft_len), + d_occupied_carriers(fft_len, false), + d_pilot_carriers(pilot_carriers.size(), std::vector<bool>(fft_len, false)), + d_pilot_symbols(pilot_symbols.size(), std::vector<gr_complex>(fft_len, gr_complex(0, 0))), + d_symbols_skipped(symbols_skipped), + d_pilot_carr_set(symbols_skipped), + d_channel_state(fft_len, gr_complex(1, 0)) +{ + int fft_shift_width = 0; + if (input_is_shifted) { + fft_shift_width = fft_len/2; + } + if (!occupied_carriers.size()) { + std::fill(d_occupied_carriers.begin(), d_occupied_carriers.end(), true); + } else { + for (unsigned i = 0; i < occupied_carriers.size(); i++) { + for (unsigned k = 0; k < occupied_carriers[i].size(); k++) { + int carr_index = occupied_carriers[i][k]; + if (occupied_carriers[i][k] < 0) { + carr_index += fft_len; + } + if (carr_index >= fft_len || carr_index < 0) { + throw std::invalid_argument("data carrier index out of bounds."); + } + d_occupied_carriers[(carr_index + fft_shift_width) % fft_len] = true; + } + } + } + if (pilot_carriers.size()) { + for (unsigned i = 0; i < pilot_carriers.size(); i++) { + if (pilot_carriers[i].size() != pilot_symbols[i].size()) { + throw std::invalid_argument("pilot carriers and -symbols do not match."); + } + for (unsigned k = 0; k < pilot_carriers[i].size(); k++) { + int carr_index = pilot_carriers[i][k]; + if (pilot_carriers[i][k] < 0) { + carr_index += fft_len; + } + if (carr_index >= fft_len || carr_index < 0) { + throw std::invalid_argument("pilot carrier index out of bounds."); + } + d_pilot_carriers[i][(carr_index + fft_shift_width) % fft_len] = true; + d_pilot_symbols[i][(carr_index + fft_shift_width) % fft_len] = pilot_symbols[i][k]; + } + } + } +} + + +digital_ofdm_equalizer_1d_pilots::~digital_ofdm_equalizer_1d_pilots() +{ +} + + +void +digital_ofdm_equalizer_1d_pilots::reset() +{ + std::fill(d_channel_state.begin(), d_channel_state.end(), gr_complex(1, 0)); + d_pilot_carr_set = d_symbols_skipped; +} + + +void digital_ofdm_equalizer_1d_pilots::get_channel_state(std::vector<gr_complex> &taps) +{ + taps = d_channel_state; +} + + diff --git a/gr-digital/lib/digital_ofdm_equalizer_simpledfe.cc b/gr-digital/lib/digital_ofdm_equalizer_simpledfe.cc new file mode 100644 index 0000000000..9abab8c1dd --- /dev/null +++ b/gr-digital/lib/digital_ofdm_equalizer_simpledfe.cc @@ -0,0 +1,101 @@ +/* -*- c++ -*- */ +/* Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "digital_ofdm_equalizer_simpledfe.h" + +digital_ofdm_equalizer_simpledfe_sptr +digital_make_ofdm_equalizer_simpledfe( + int fft_len, + const digital_constellation_sptr &constellation, + const std::vector<std::vector<int> > &occupied_carriers, + const std::vector<std::vector<int> > &pilot_carriers, + const std::vector<std::vector<gr_complex> > &pilot_symbols, + int symbols_skipped, + float alpha, + bool input_is_shifted) +{ + return digital_ofdm_equalizer_simpledfe_sptr(new digital_ofdm_equalizer_simpledfe( + fft_len, + constellation, + occupied_carriers, + pilot_carriers, + pilot_symbols, + symbols_skipped, + alpha, + input_is_shifted)); +} + +digital_ofdm_equalizer_simpledfe::digital_ofdm_equalizer_simpledfe( + int fft_len, + const digital_constellation_sptr &constellation, + const std::vector<std::vector<int> > &occupied_carriers, + const std::vector<std::vector<int> > &pilot_carriers, + const std::vector<std::vector<gr_complex> > &pilot_symbols, + int symbols_skipped, + float alpha, + bool input_is_shifted) + : digital_ofdm_equalizer_1d_pilots(fft_len, occupied_carriers, pilot_carriers, pilot_symbols, symbols_skipped, input_is_shifted), + d_constellation(constellation), + d_alpha(alpha) +{ +} + + +digital_ofdm_equalizer_simpledfe::~digital_ofdm_equalizer_simpledfe() +{ +} + + +void +digital_ofdm_equalizer_simpledfe::equalize(gr_complex *frame, + int n_sym, + const std::vector<gr_complex> &initial_taps, + const std::vector<gr_tag_t> &tags) +{ + if (!initial_taps.empty()) { + d_channel_state = initial_taps; + } + gr_complex sym_eq, sym_est; + + for (int i = 0; i < n_sym; i++) { + for (int k = 0; k < d_fft_len; k++) { + if (!d_occupied_carriers[k]) { + continue; + } + if (d_pilot_carriers.size() && d_pilot_carriers[d_pilot_carr_set][k-d_carr_offset]) { + d_channel_state[k] = d_alpha * d_channel_state[k] + + (1-d_alpha) * frame[i*d_fft_len + k] / d_pilot_symbols[d_pilot_carr_set][k-d_carr_offset]; + frame[i*d_fft_len+k] = d_pilot_symbols[d_pilot_carr_set][k-d_carr_offset]; + } else { + sym_eq = frame[i*d_fft_len+k] / d_channel_state[k]; + d_constellation->map_to_points(d_constellation->decision_maker(&sym_eq), &sym_est); + d_channel_state[k] = d_alpha * d_channel_state[k] + frame[i*d_fft_len+k] / sym_est; + frame[i*d_fft_len+k] = sym_est; + } + } + d_pilot_carr_set = (d_pilot_carr_set + 1) % d_pilot_carriers.size(); + } +} + diff --git a/gr-digital/lib/digital_ofdm_equalizer_static.cc b/gr-digital/lib/digital_ofdm_equalizer_static.cc new file mode 100644 index 0000000000..66903fa90a --- /dev/null +++ b/gr-digital/lib/digital_ofdm_equalizer_static.cc @@ -0,0 +1,90 @@ +/* -*- c++ -*- */ +/* Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "digital_ofdm_equalizer_static.h" + +#include <iostream> + +digital_ofdm_equalizer_static_sptr +digital_make_ofdm_equalizer_static( + int fft_len, + const std::vector<std::vector<int> > &occupied_carriers, + const std::vector<std::vector<int> > &pilot_carriers, + const std::vector<std::vector<gr_complex> > &pilot_symbols, + int symbols_skipped, + bool input_is_shifted) +{ + return digital_ofdm_equalizer_static_sptr(new digital_ofdm_equalizer_static( + fft_len, + occupied_carriers, + pilot_carriers, + pilot_symbols, + symbols_skipped, + input_is_shifted)); +} + +digital_ofdm_equalizer_static::digital_ofdm_equalizer_static( + int fft_len, + const std::vector<std::vector<int> > &occupied_carriers, + const std::vector<std::vector<int> > &pilot_carriers, + const std::vector<std::vector<gr_complex> > &pilot_symbols, + int symbols_skipped, + bool input_is_shifted) + : digital_ofdm_equalizer_1d_pilots(fft_len, occupied_carriers, pilot_carriers, pilot_symbols, symbols_skipped, input_is_shifted) +{ +} + + +digital_ofdm_equalizer_static::~digital_ofdm_equalizer_static() +{ +} + + +void +digital_ofdm_equalizer_static::equalize(gr_complex *frame, + int n_sym, + const std::vector<gr_complex> &initial_taps, + const std::vector<gr_tag_t> &tags) +{ + d_channel_state = initial_taps; + + for (int i = 0; i < n_sym; i++) { + for (int k = 0; k < d_fft_len; k++) { + if (!d_occupied_carriers[k]) { + continue; + } + if (d_pilot_carriers.size() && d_pilot_carriers[d_pilot_carr_set][k-d_carr_offset]) { + d_channel_state[k] = frame[i*d_fft_len + k] / d_pilot_symbols[d_pilot_carr_set][k-d_carr_offset]; + frame[i*d_fft_len+k] = d_pilot_symbols[d_pilot_carr_set][k-d_carr_offset]; + } else { + frame[i*d_fft_len+k] /= d_channel_state[k]; + } + } + if (!d_pilot_carriers.empty()) { + d_pilot_carr_set = (d_pilot_carr_set + 1) % d_pilot_carriers.size(); + } + } +} + diff --git a/gr-digital/lib/digital_ofdm_sync_sc_cfb.cc b/gr-digital/lib/digital_ofdm_sync_sc_cfb.cc new file mode 100644 index 0000000000..a3ebd549cb --- /dev/null +++ b/gr-digital/lib/digital_ofdm_sync_sc_cfb.cc @@ -0,0 +1,109 @@ +/* -*- c++ -*- */ +/* Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gr_io_signature.h> +#include "digital_ofdm_sync_sc_cfb.h" + +#include <gr_delay.h> +#include <blocks/conjugate_cc.h> +#include <blocks/multiply_cc.h> +#include <filter/fir_filter_ccf.h> +#include <blocks/complex_to_mag_squared.h> +#include <filter/fir_filter_fff.h> +#include <blocks/multiply_ff.h> +#include <blocks/divide_ff.h> +#include <blocks/complex_to_arg.h> +#include <analog/plateau_detector_fb.h> +#include <gr_sample_and_hold_ff.h> + +// Define this to add a third output for debugging +//#define SYNC_ADD_DEBUG_OUTPUT + +digital_ofdm_sync_sc_cfb_sptr +digital_make_ofdm_sync_sc_cfb (int fft_len, int cp_len) +{ + return gnuradio::get_initial_sptr (new digital_ofdm_sync_sc_cfb(fft_len, cp_len)); +} + + +digital_ofdm_sync_sc_cfb::digital_ofdm_sync_sc_cfb (int fft_len, int cp_len) + : gr_hier_block2 ("ofdm_sync_sc_cfb", + gr_make_io_signature(1, 1, sizeof (gr_complex)), +#ifndef SYNC_ADD_DEBUG_OUTPUT + gr_make_io_signature2(2, 2, sizeof (float), sizeof (unsigned char))) +#else + gr_make_io_signature3(3, 3, sizeof (float), sizeof (unsigned char), sizeof (float))) +#endif +{ + std::vector<float> ma_taps(fft_len/2, 1.0); + gr_delay_sptr delay(gr_make_delay(sizeof(gr_complex), fft_len/2)); + gr::blocks::conjugate_cc::sptr delay_conjugate(gr::blocks::conjugate_cc::make()); + gr::blocks::multiply_cc::sptr delay_corr(gr::blocks::multiply_cc::make()); + gr::filter::fir_filter_ccf::sptr delay_ma(gr::filter::fir_filter_ccf::make(1, std::vector<float>(fft_len/2, 1.0))); + gr::blocks::complex_to_mag_squared::sptr delay_magsquare(gr::blocks::complex_to_mag_squared::make()); + gr::blocks::divide_ff::sptr delay_normalize(gr::blocks::divide_ff::make()); + + gr::blocks::complex_to_mag_squared::sptr normalizer_magsquare(gr::blocks::complex_to_mag_squared::make()); + gr::filter::fir_filter_fff::sptr normalizer_ma(gr::filter::fir_filter_fff::make(1, std::vector<float>(fft_len, 0.5))); + gr::blocks::multiply_ff::sptr normalizer_square(gr::blocks::multiply_ff::make()); + + gr::blocks::complex_to_arg::sptr peak_to_angle(gr::blocks::complex_to_arg::make()); + gr_sample_and_hold_ff_sptr sample_and_hold(gr_make_sample_and_hold_ff()); + + gr::analog::plateau_detector_fb::sptr plateau_detector(gr::analog::plateau_detector_fb::make(cp_len)); + + // Delay Path + connect(self(), 0, delay, 0); + connect(delay, 0, delay_conjugate, 0); + connect(delay_conjugate, 0, delay_corr, 1); + connect(self(), 0, delay_corr, 0); + connect(delay_corr, 0, delay_ma, 0); + connect(delay_ma, 0, delay_magsquare, 0); + connect(delay_magsquare, 0, delay_normalize, 0); + // Energy Path + connect(self(), 0, normalizer_magsquare, 0); + connect(normalizer_magsquare, 0, normalizer_ma, 0); + connect(normalizer_ma, 0, normalizer_square, 0); + connect(normalizer_ma, 0, normalizer_square, 1); + connect(normalizer_square, 0, delay_normalize, 1); + // Fine frequency estimate (output 0) + connect(delay_ma, 0, peak_to_angle, 0); + connect(peak_to_angle, 0, sample_and_hold, 0); + connect(sample_and_hold, 0, self(), 0); + // Peak detect (output 1) + connect(delay_normalize, 0, plateau_detector, 0); + connect(plateau_detector, 0, sample_and_hold, 1); + connect(plateau_detector, 0, self(), 1); +#ifdef SYNC_ADD_DEBUG_OUTPUT + // Debugging: timing metric (output 2) + connect(delay_normalize, 0, self(), 2); +#endif +} + + +digital_ofdm_sync_sc_cfb::~digital_ofdm_sync_sc_cfb() +{ +} + diff --git a/gr-digital/lib/header_payload_demux_impl.cc b/gr-digital/lib/header_payload_demux_impl.cc new file mode 100644 index 0000000000..f79678e903 --- /dev/null +++ b/gr-digital/lib/header_payload_demux_impl.cc @@ -0,0 +1,292 @@ +/* -*- c++ -*- */ +/* Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <climits> +#include <gr_io_signature.h> +#include "header_payload_demux_impl.h" + +namespace gr { + namespace digital { + + enum demux_states_t { + STATE_IDLE, + STATE_HEADER, + STATE_WAIT_FOR_MSG, + STATE_PAYLOAD + }; + +#define msg_port_id pmt::mp("header_data") + + header_payload_demux::sptr + header_payload_demux::make( + int header_len, + int items_per_symbol, + int guard_interval, + const std::string &length_tag_key, + const std::string &trigger_tag_key, + bool output_symbols, + size_t itemsize) + { + return gnuradio::get_initial_sptr ( + new header_payload_demux_impl( + header_len, + items_per_symbol, + guard_interval, + length_tag_key, + trigger_tag_key, + output_symbols, + itemsize + ) + ); + } + + header_payload_demux_impl::header_payload_demux_impl( + int header_len, + int items_per_symbol, + int guard_interval, + const std::string &length_tag_key, + const std::string &trigger_tag_key, + bool output_symbols, + size_t itemsize + ) : gr_block("header_payload_demux", + gr_make_io_signature2(1, 2, itemsize, sizeof(char)), + gr_make_io_signature(2, 2, (output_symbols ? itemsize * items_per_symbol : itemsize))), + d_header_len(header_len), + d_items_per_symbol(items_per_symbol), + d_gi(guard_interval), + d_len_tag_key(pmt::pmt_string_to_symbol(length_tag_key)), + d_trigger_tag_key(pmt::pmt_string_to_symbol(trigger_tag_key)), + d_output_symbols(output_symbols), + d_itemsize(itemsize), + d_uses_trigger_tag(!trigger_tag_key.empty()), + d_state(STATE_IDLE) + { + if (d_header_len < 1) { + throw std::invalid_argument("Header length must be at least 1 symbol."); + } + if (d_items_per_symbol < 1 || d_gi < 0 || d_itemsize < 1) { + throw std::invalid_argument("Items and symbol sizes must be at least 1."); + } + set_output_multiple(d_items_per_symbol); + message_port_register_in(msg_port_id); + } + + header_payload_demux_impl::~header_payload_demux_impl() + { + } + + void + header_payload_demux_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required) + { + // noutput_items is an integer multiple of d_items_per_symbol! + for (unsigned i = 0; i < ninput_items_required.size(); i++) { + ninput_items_required[i] = + noutput_items / d_items_per_symbol * (d_items_per_symbol + d_gi); + } + } + + int + header_payload_demux_impl::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const unsigned char *in = (const unsigned char *) input_items[0]; + unsigned char *out_header = (unsigned char *) output_items[0]; + unsigned char *out_payload = (unsigned char *) output_items[1]; + + int nread = 0; + bool exit_loop = false; + + int produced_hdr = 0; + int produced_payload = 0; + + while (nread < noutput_items && !exit_loop) { + switch (d_state) { + case STATE_IDLE: + // 1) Search for a trigger signal on input 1 (if present) + // 2) Search for a trigger tag, make sure it's the first one + // The first trigger to be found is used! + // 3) Make sure the right number of items is skipped + // 4) If trigger found, switch to STATE_HEADER + if (find_trigger_signal(nread, noutput_items, input_items)) { + d_remaining_symbols = d_header_len; + d_state = STATE_HEADER; + in += nread * d_itemsize; + } + break; + + case STATE_HEADER: + copy_symbol(in, out_header, 0, nread, produced_hdr); + if (d_remaining_symbols == 0) { + d_state = STATE_WAIT_FOR_MSG; + exit_loop = true; + } + break; + + case STATE_WAIT_FOR_MSG: + // If we're in this state, nread is zero (because previous state exits loop) + // 1) Wait for msg (blocking call) + // 2) set d_remaining_symbols + // 3) Write tags + // 4) fall through to next state + d_remaining_symbols = -1; + if (!parse_header_data_msg()) { + exit_loop = true; + break; + } + d_state = STATE_PAYLOAD; + + case STATE_PAYLOAD: + copy_symbol(in, out_payload, 1, nread, produced_payload); + if (d_remaining_symbols == 0) { + d_state = STATE_IDLE; + exit_loop = true; + } + break; + + default: + throw std::runtime_error("invalid state"); + } /* switch */ + } /* while(nread < noutput_items) */ + + if (!d_output_symbols) { + produced_hdr *= d_items_per_symbol; + produced_payload *= d_items_per_symbol; + } + produce(0, produced_hdr); + produce(1, produced_payload); + consume_each (nread); + return WORK_CALLED_PRODUCE; + } /* general_work() */ + + + bool + header_payload_demux_impl::find_trigger_signal( + int &pos, + int noutput_items, + gr_vector_const_void_star &input_items) + { + if (input_items.size() == 2) { + unsigned char *in_trigger = (unsigned char *) input_items[1]; + for (int i = 0; i < noutput_items; i++) { + if (in_trigger[i]) { + pos = i; + return true; + } + } + } + if (d_uses_trigger_tag) { + std::vector<gr_tag_t> tags; + get_tags_in_range(tags, 0, nitems_read(0), nitems_read(0)+noutput_items); + uint64_t min_offset = ULLONG_MAX; + int tag_index = -1; + for (unsigned i = 0; i < tags.size(); i++) { + if (tags[i].key == d_trigger_tag_key && tags[i].offset < min_offset) { + tag_index = (int) i; + min_offset = tags[i].offset; + } + } + if (tag_index != -1) { + pos = min_offset - nitems_read(0); + return true; + } + } + pos += noutput_items; + return false; + } + + + bool + header_payload_demux_impl::parse_header_data_msg() + { + pmt::pmt_t msg(delete_head_blocking(msg_port_id)); + if (pmt::pmt_is_integer(msg)) { + d_remaining_symbols = pmt::pmt_to_long(msg); + add_item_tag(1, nitems_written(1), d_len_tag_key, msg); + } else if (pmt::pmt_is_dict(msg)) { + pmt::pmt_t dict_items(pmt::pmt_dict_items(msg)); + while (!pmt::pmt_is_null(dict_items)) { + pmt::pmt_t this_item(pmt::pmt_car(dict_items)); + add_item_tag(1, nitems_written(1), pmt::pmt_car(this_item), pmt::pmt_cdr(this_item)); + if (pmt::pmt_equal(pmt::pmt_car(this_item), d_len_tag_key)) { + d_remaining_symbols = pmt::pmt_to_long(pmt::pmt_cdr(this_item)); + } + dict_items = pmt::pmt_cdr(dict_items); + } + if (d_remaining_symbols == -1) { + throw std::runtime_error("no length tag passed from header data"); + } + } else if (pmt::pmt_is_null(msg)) { // Blocking call was interrupted + return false; + } else { + throw std::runtime_error("Received illegal header data"); + } + return true; + } + + void + header_payload_demux_impl::copy_symbol(const unsigned char *&in, unsigned char *&out, int port, int &nread, int &nproduced) + { + std::vector<gr_tag_t> tags; + memcpy((void *) out, + (void *) (in + d_gi * d_itemsize), + d_itemsize * d_items_per_symbol + ); + // Tags on GI + get_tags_in_range(tags, 0, + nitems_read(0) + nread, + nitems_read(0) + nread + d_gi + ); + for (unsigned t = 0; t < tags.size(); t++) { + add_item_tag(port, + nitems_written(port)+nproduced, + tags[t].key, + tags[t].value + ); + } + // Tags on symbol + get_tags_in_range( + tags, 0, + nitems_read(port) + nread + d_gi, + nitems_read(port) + nread + d_gi + d_items_per_symbol + ); + for (unsigned t = 0; t < tags.size(); t++) { + add_item_tag(0, + tags[t].offset - nitems_read(0)-nread + nitems_written(port)+nproduced, + tags[t].key, + tags[t].value + ); + } + in += d_itemsize * (d_items_per_symbol + d_gi); + out += d_items_per_symbol * d_itemsize; + nread += d_items_per_symbol + d_gi; + nproduced++; + d_remaining_symbols--; + } + + } /* namespace digital */ +} /* namespace gr */ + diff --git a/gr-digital/lib/header_payload_demux_impl.h b/gr-digital/lib/header_payload_demux_impl.h new file mode 100644 index 0000000000..ceab9a8629 --- /dev/null +++ b/gr-digital/lib/header_payload_demux_impl.h @@ -0,0 +1,85 @@ +/* -*- c++ -*- */ +/* Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DIGITAL_HEADER_PAYLOAD_DEMUX_IMPL_H +#define INCLUDED_DIGITAL_HEADER_PAYLOAD_DEMUX_IMPL_H + +#include <digital/header_payload_demux.h> + +namespace gr { + namespace digital { + + class header_payload_demux_impl : public header_payload_demux + { + private: + int d_header_len; //! Number of bytes per header + int d_items_per_symbol; //! Bytes per symbol + int d_gi; //! Bytes per guard interval + pmt::pmt_t d_len_tag_key; //! Key of length tag + pmt::pmt_t d_trigger_tag_key; //! Key of trigger tag (if used) + bool d_output_symbols; //! If true, output is symbols, not items + size_t d_itemsize; //! Bytes per item + bool d_uses_trigger_tag; //! If a trigger tag is used + int d_ninput_items_reqd; //! Helper for forecast() + int d_state; //! Current read state + int d_remaining_symbols; //! When in payload or header state, the number of symbols still to transmit + + // Helpers to make the state machine more readable + + //! Helper function that does the reading from the msg port + bool parse_header_data_msg(); + + //! Helper function that returns true if a trigger signal is detected. + // Searches input 1 (if active), then the tags. Sets \p pos to the position + // of the first tag. + bool find_trigger_signal( + int &pos, + int noutput_items, + gr_vector_const_void_star &input_items); + + //! Helper function, copies one symbol from in to out and updates all pointers and counters + void copy_symbol(const unsigned char *&in, unsigned char *&out, int port, int &nread, int &nproduced); + + public: + + header_payload_demux_impl( + int header_len, + int items_per_symbol, + int guard_interval, + const std::string &length_tag_key, + const std::string &trigger_tag_key, + bool output_symbols, + size_t itemsize); + ~header_payload_demux_impl(); + + void forecast (int noutput_items, gr_vector_int &ninput_items_required); + + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } // namespace digital +} // namespace gr + +#endif /* INCLUDED_DIGITAL_HEADER_PAYLOAD_DEMUX_IMPL_H */ + diff --git a/gr-digital/lib/ofdm_frame_equalizer_vcvc_impl.cc b/gr-digital/lib/ofdm_frame_equalizer_vcvc_impl.cc new file mode 100644 index 0000000000..e9391658b6 --- /dev/null +++ b/gr-digital/lib/ofdm_frame_equalizer_vcvc_impl.cc @@ -0,0 +1,89 @@ +/* -*- c++ -*- */ +/* Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gr_io_signature.h> +#include "ofdm_frame_equalizer_vcvc_impl.h" + +namespace gr { + namespace digital { + + ofdm_frame_equalizer_vcvc::sptr + ofdm_frame_equalizer_vcvc::make(digital_ofdm_equalizer_base_sptr equalizer, const std::string &len_tag_key, bool propagate_channel_state) + { + return gnuradio::get_initial_sptr (new ofdm_frame_equalizer_vcvc_impl(equalizer, len_tag_key, propagate_channel_state)); + } + + ofdm_frame_equalizer_vcvc_impl::ofdm_frame_equalizer_vcvc_impl(digital_ofdm_equalizer_base_sptr equalizer, const std::string &len_tag_key, bool propagate_channel_state) + : gr_tagged_stream_block("ofdm_frame_equalizer_vcvc", + gr_make_io_signature(1, 1, sizeof (gr_complex) * equalizer->fft_len()), + gr_make_io_signature(1, 1, sizeof (gr_complex) * equalizer->fft_len()), + len_tag_key), + d_fft_len(equalizer->fft_len()), + d_eq(equalizer), + d_propagate_channel_state(propagate_channel_state), + d_channel_state(equalizer->fft_len(), gr_complex(1, 0)) + {} + + ofdm_frame_equalizer_vcvc_impl::~ofdm_frame_equalizer_vcvc_impl() + { + } + + + int + ofdm_frame_equalizer_vcvc_impl::work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const gr_complex *in = (const gr_complex *) input_items[0]; + gr_complex *out = (gr_complex *) output_items[0]; + int carrier_offset = 0; + + std::vector<gr_tag_t> tags; + get_tags_in_range(tags, 0, nitems_read(0), nitems_read(0)+1); + for (unsigned i = 0; i < tags.size(); i++) { + if (pmt::pmt_symbol_to_string(tags[i].key) == "ofdm_sync_chan_taps") { + d_channel_state = pmt::pmt_c32vector_elements(tags[i].value); + remove_item_tag(0, tags[i]); + } + } + + memcpy((void *) out, (void *) in, sizeof(gr_complex) * d_fft_len * ninput_items[0]); + d_eq->reset(); + d_eq->set_carrier_offset(carrier_offset); + d_eq->equalize(out, ninput_items[0], d_channel_state); + d_eq->get_channel_state(d_channel_state); + if (d_propagate_channel_state) { + add_item_tag(0, nitems_written(0), + pmt::pmt_string_to_symbol("ofdm_sync_chan_taps"), + pmt::pmt_init_c32vector(d_fft_len, d_channel_state)); + } + + return ninput_items[0]; + } + + } /* namespace digital */ +} /* namespace gr */ + diff --git a/gr-digital/lib/ofdm_frame_equalizer_vcvc_impl.h b/gr-digital/lib/ofdm_frame_equalizer_vcvc_impl.h new file mode 100644 index 0000000000..cba2d513ea --- /dev/null +++ b/gr-digital/lib/ofdm_frame_equalizer_vcvc_impl.h @@ -0,0 +1,57 @@ +/* -*- c++ -*- */ +/* Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DIGITAL_OFDM_FRAME_EQUALIZER_VCVC_IMPL_H +#define INCLUDED_DIGITAL_OFDM_FRAME_EQUALIZER_VCVC_IMPL_H + +#include <digital/ofdm_frame_equalizer_vcvc.h> + +namespace gr { + namespace digital { + + class ofdm_frame_equalizer_vcvc_impl : public ofdm_frame_equalizer_vcvc + { + private: + const int d_fft_len; + digital_ofdm_equalizer_base_sptr d_eq; + bool d_propagate_channel_state; + std::vector<gr_complex> d_channel_state; + + protected: + // This aren't really necessary, so let's override them with nuthin' + void remove_length_tags(const std::vector<std::vector<gr_tag_t> > &tags) {}; + void update_length_tags(int n_produced, int n_ports) {}; + + public: + ofdm_frame_equalizer_vcvc_impl(digital_ofdm_equalizer_base_sptr equalizer, const std::string &len_tag_key, bool propagate_channel_state); + ~ofdm_frame_equalizer_vcvc_impl(); + + int work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } // namespace digital +} // namespace gr + +#endif /* INCLUDED_DIGITAL_OFDM_FRAME_EQUALIZER_VCVC_IMPL_H */ + diff --git a/gr-digital/lib/ofdm_serializer_vcc_impl.cc b/gr-digital/lib/ofdm_serializer_vcc_impl.cc new file mode 100644 index 0000000000..2fdb9bd0e8 --- /dev/null +++ b/gr-digital/lib/ofdm_serializer_vcc_impl.cc @@ -0,0 +1,205 @@ +/* -*- c++ -*- */ +/* Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gr_io_signature.h> +#include "ofdm_serializer_vcc_impl.h" + +namespace gr { + namespace digital { + + ofdm_serializer_vcc::sptr + ofdm_serializer_vcc::make( + int fft_len, + const std::vector<std::vector<int> > &occupied_carriers, + const std::string &len_tag_key, + const std::string &packet_len_tag_key, + int symbols_skipped, + bool input_is_shifted + ) + { + return gnuradio::get_initial_sptr ( + new ofdm_serializer_vcc_impl( + fft_len, occupied_carriers, + len_tag_key, packet_len_tag_key, + symbols_skipped, input_is_shifted + ) + ); + } + + ofdm_serializer_vcc::sptr + ofdm_serializer_vcc::make( + const digital_ofdm_carrier_allocator_cvc_sptr &allocator, + const std::string &packet_len_tag_key, + int symbols_skipped, + bool input_is_shifted + ) + { + return gnuradio::get_initial_sptr( + new ofdm_serializer_vcc_impl( + allocator->fft_len(), + allocator->occupied_carriers(), + allocator->len_tag_key(), + packet_len_tag_key, + symbols_skipped, + input_is_shifted + ) + ); + } + + ofdm_serializer_vcc_impl::ofdm_serializer_vcc_impl ( + int fft_len, + const std::vector<std::vector<int> > &occupied_carriers, + const std::string &len_tag_key, + const std::string &packet_len_tag_key, + int symbols_skipped, + bool input_is_shifted) + : gr_tagged_stream_block ("ofdm_serializer_vcc", + gr_make_io_signature(1, 1, sizeof (gr_complex) * fft_len), + gr_make_io_signature(1, 1, sizeof (gr_complex)), + len_tag_key), + d_fft_len(fft_len), + d_occupied_carriers(occupied_carriers), + d_packet_len_tag_key(pmt::pmt_string_to_symbol(packet_len_tag_key)), + d_out_len_tag_key(pmt::pmt_string_to_symbol((packet_len_tag_key.empty() ? len_tag_key : packet_len_tag_key))), + d_symbols_skipped(symbols_skipped % occupied_carriers.size()), + d_curr_set(symbols_skipped % occupied_carriers.size()), + d_symbols_per_set(0) + { + for (unsigned i = 0; i < d_occupied_carriers.size(); i++) { + for (unsigned k = 0; k < d_occupied_carriers[i].size(); k++) { + if (d_occupied_carriers[i][k] < 0) { + d_occupied_carriers[i][k] += fft_len; + } + if (d_occupied_carriers[i][k] >= fft_len || d_occupied_carriers[i][k] < 0) { + throw std::invalid_argument("ofdm_serializer_vcc: trying to occupy a carrier outside the fft length."); + } + if (input_is_shifted) { + d_occupied_carriers[i][k] = (d_occupied_carriers[i][k] + fft_len) % fft_len; + } + } + } + + for (unsigned i = 0; i < d_occupied_carriers.size(); i++) { + d_symbols_per_set += d_occupied_carriers[i].size(); + } + set_relative_rate((double) d_symbols_per_set / d_occupied_carriers.size()); + set_tag_propagation_policy(TPP_DONT); + } + + ofdm_serializer_vcc_impl::~ofdm_serializer_vcc_impl() + { + } + + int + ofdm_serializer_vcc_impl::calculate_output_stream_length(const gr_vector_int &ninput_items) + { + int nout = (ninput_items[0] / d_occupied_carriers.size()) * d_symbols_per_set; + for (unsigned i = 0; i < ninput_items[0] % d_occupied_carriers.size(); i++) { + nout += d_occupied_carriers[(i + d_curr_set) % d_occupied_carriers.size()].size(); + } + return nout; + } + + void + ofdm_serializer_vcc_impl::update_length_tags(int n_produced, int n_ports) + { + add_item_tag(0, nitems_written(0), + d_out_len_tag_key, + pmt::pmt_from_long(n_produced) + ); + } + + int + ofdm_serializer_vcc_impl::work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const gr_complex *in = (const gr_complex *) input_items[0]; + gr_complex *out = (gr_complex *) output_items[0]; + long frame_length = ninput_items[0]; // Input frame + long packet_length = 0; // Output frame + int carr_offset = 0; + + std::vector<gr_tag_t> tags; + // Packet mode + if (!d_length_tag_key_str.empty()) { + get_tags_in_range(tags, 0, nitems_read(0), nitems_read(0)+1); + for (unsigned i = 0; i < tags.size(); i++) { + if (pmt::pmt_symbol_to_string(tags[i].key) == "ofdm_sync_carr_offset") { + carr_offset = pmt::pmt_to_long(tags[i].value); + } + if (tags[i].key == d_packet_len_tag_key) { + packet_length = pmt::pmt_to_long(tags[i].value); + remove_item_tag(0, tags[i]); + } + } + } else { + // recalc frame length from noutput_items + frame_length = 0; + int sym_per_frame = 0; + while ((sym_per_frame + d_occupied_carriers[(frame_length + 1) % d_occupied_carriers.size()].size()) < noutput_items) { + frame_length++; + sym_per_frame += d_occupied_carriers[(frame_length + 1) % d_occupied_carriers.size()].size(); + } + } + + // Copy symbols + int n_out_symbols = 0; + for (int i = 0; i < frame_length; i++) { + // Copy all tags associated with this input OFDM symbol onto the first output symbol + get_tags_in_range(tags, 0, + nitems_read(0)+i, + nitems_read(0)+i+1 + ); + for (unsigned t = 0; t < tags.size(); t++) { + add_item_tag(0, nitems_written(0)+n_out_symbols, + tags[i].key, + tags[i].value + ); + } + for (unsigned k = 0; k < d_occupied_carriers[d_curr_set].size(); k++) { + out[n_out_symbols++] = in[i * d_fft_len + d_occupied_carriers[d_curr_set][k] + carr_offset]; + } + if (packet_length && n_out_symbols > packet_length) { + n_out_symbols = packet_length; + break; + } + d_curr_set = (d_curr_set + 1) % d_occupied_carriers.size(); + } + + // Housekeeping + if (d_length_tag_key_str.empty()) { + consume_each(frame_length); + } else { + d_curr_set = d_symbols_skipped; + } + + return n_out_symbols; + } + + } /* namespace digital */ +} /* namespace gr */ + diff --git a/gr-digital/lib/ofdm_serializer_vcc_impl.h b/gr-digital/lib/ofdm_serializer_vcc_impl.h new file mode 100644 index 0000000000..ef2f1c83b1 --- /dev/null +++ b/gr-digital/lib/ofdm_serializer_vcc_impl.h @@ -0,0 +1,69 @@ +/* -*- c++ -*- */ +/* Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DIGITAL_OFDM_SERIALIZER_VCC_IMPL_H +#define INCLUDED_DIGITAL_OFDM_SERIALIZER_VCC_IMPL_H + +#include <digital/ofdm_serializer_vcc.h> + +namespace gr { + namespace digital { + + class ofdm_serializer_vcc_impl : public ofdm_serializer_vcc + { + private: + int d_fft_len; //! FFT length + std::vector<std::vector<int> > d_occupied_carriers; //! Which carriers/symbols carry data + pmt::pmt_t d_packet_len_tag_key; //! Key of the length tag + pmt::pmt_t d_out_len_tag_key; //! Key of the length tag + const int d_symbols_skipped; //! Start position in d_occupied_carriers + int d_curr_set; //! Current position in d_occupied_carriers + int d_symbols_per_set; + + protected: + /* Calculate the number of scalar complex symbols given a number of + * OFDM symbols. + */ + int calculate_output_stream_length(const gr_vector_int &ninput_items); + void update_length_tags(int n_produced, int n_ports); + + public: + ofdm_serializer_vcc_impl( + int fft_len, + const std::vector<std::vector<int> > &occupied_carriers, + const std::string &len_tag_key, + const std::string &packet_len_tag_key, + int symbols_skipped, + bool input_is_shifted + ); + ~ofdm_serializer_vcc_impl(); + + int work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } // namespace digital +} // namespace gr + +#endif /* INCLUDED_DIGITAL_OFDM_SERIALIZER_VCC_IMPL_H */ + diff --git a/gr-digital/lib/packet_header_default.cc b/gr-digital/lib/packet_header_default.cc new file mode 100644 index 0000000000..dac57512d3 --- /dev/null +++ b/gr-digital/lib/packet_header_default.cc @@ -0,0 +1,128 @@ +/* -*- c++ -*- */ +/* Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <digital/packet_header_default.h> + +namespace gr { + namespace digital { + + packet_header_default::sptr + packet_header_default::make( + long header_len, + const std::string &len_tag_key, + const std::string &num_tag_key, + int bits_per_byte) + { + return packet_header_default::sptr(new packet_header_default(header_len, len_tag_key, num_tag_key, bits_per_byte)); + } + + const unsigned MASK_LUT[9] = {0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x2F, 0x7F, 0xFF}; + packet_header_default::packet_header_default( + long header_len, + const std::string &len_tag_key, + const std::string &num_tag_key, + int bits_per_byte) + : d_header_len(header_len), + d_len_tag_key(pmt::pmt_string_to_symbol(len_tag_key)), + d_num_tag_key(pmt::pmt_string_to_symbol(num_tag_key)), + d_bits_per_byte(bits_per_byte), + d_header_number(0) + { + if (d_bits_per_byte < 1 || d_bits_per_byte > 8) { + throw std::invalid_argument("bits_per_byte must be in [1, 8]"); + } + d_mask = MASK_LUT[d_bits_per_byte]; + } + + packet_header_default::~packet_header_default() + { + } + + bool packet_header_default::header_formatter( + long packet_len, + unsigned char *out, + const std::vector<gr_tag_t> &tags + ) + { + packet_len &= 0x0FFF; + + memset(out, 0x00, d_header_len); + int parity = 0; + int k = 0; // Position in out + for (int i = 0; i < 12 && k < d_header_len; i += d_bits_per_byte, k++) { + out[k] = (unsigned char) ((packet_len >> i) & d_mask); + parity += out[k]; + } + for (int i = 0; i < 16 && k < d_header_len; i += d_bits_per_byte, k++) { + out[k] = (unsigned char) ((d_header_number >> i) & d_mask); + parity += out[k]; + } + if (k < d_header_len) { + out[k] = (unsigned char) (parity % 2); + } + d_header_number++; + + return true; + } + + + bool packet_header_default::header_parser( + const unsigned char *in, + std::vector<gr_tag_t> &tags) + { + unsigned header_len = 0; + unsigned header_num = 0; + gr_tag_t tag; + + int k = 0; // Position in "in" + for (int i = 0; i < 12 && k < d_header_len; i += d_bits_per_byte, k++) { + header_len |= (((int) in[k]) & d_mask) << i; + } + tag.key = d_len_tag_key; + tag.value = pmt::pmt_from_long(header_len); + tags.push_back(tag); + if (k >= d_header_len) { + return true; + } + for (int i = 0; i < 16 && k < d_header_len; i += d_bits_per_byte, k++) { + header_num |= (((int) in[k]) & d_mask) << i; + } + tag.key = d_num_tag_key; + tag.value = pmt::pmt_from_long(header_num); + tags.push_back(tag); + if (k >= d_header_len) { + return true; + } + + int parity = in[k]; + for (int i = 0; i < 28; i++) { + parity += in[i]; + } + return !(parity % 2); + } + + } /* namespace digital */ +} /* namespace gr */ + diff --git a/gr-digital/lib/packet_header_ofdm.cc b/gr-digital/lib/packet_header_ofdm.cc new file mode 100644 index 0000000000..db190c13bb --- /dev/null +++ b/gr-digital/lib/packet_header_ofdm.cc @@ -0,0 +1,115 @@ +/* -*- c++ -*- */ +/* Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <digital/packet_header_ofdm.h> + +namespace gr { + namespace digital { + + int _get_header_len_from_occupied_carriers(const std::vector<std::vector<int> > &occupied_carriers, int n_syms) + { + int header_len = 0; + for (int i = 0; i < n_syms; i++) { + header_len += occupied_carriers[i].size(); + } + + return header_len; + } + + packet_header_ofdm::sptr + packet_header_ofdm::make( + const std::vector<std::vector<int> > &occupied_carriers, + int n_syms, + const std::string &len_tag_key, + const std::string &frame_len_tag_key, + const std::string &num_tag_key, + int bits_per_sym) + { + return packet_header_ofdm::sptr( + new packet_header_ofdm( + occupied_carriers, n_syms, len_tag_key, frame_len_tag_key, num_tag_key, bits_per_sym + ) + ); + } + + packet_header_ofdm::packet_header_ofdm( + const std::vector<std::vector<int> > &occupied_carriers, + int n_syms, + const std::string &len_tag_key, + const std::string &frame_len_tag_key, + const std::string &num_tag_key, + int bits_per_sym) + : packet_header_default( + _get_header_len_from_occupied_carriers(occupied_carriers, n_syms), + len_tag_key, + num_tag_key, + bits_per_sym), + d_frame_len_tag_key(pmt::pmt_string_to_symbol(frame_len_tag_key)), + d_occupied_carriers(occupied_carriers), + d_syms_per_set(0) + { + for (unsigned i = 0; i < d_occupied_carriers.size(); i++) { + d_syms_per_set += d_occupied_carriers[i].size(); + } + } + + packet_header_ofdm::~packet_header_ofdm() + { + } + + + bool packet_header_ofdm::header_parser( + const unsigned char *in, + std::vector<gr_tag_t> &tags) + { + if (!packet_header_default::header_parser(in, tags)) { + return false; + } + int packet_len = 0; // # of OFDM symbols + for (unsigned i = 0; i < tags.size(); i++) { + if (pmt::pmt_equal(tags[i].key, d_len_tag_key)) { + packet_len = pmt::pmt_to_long(tags[i].value); + break; + } + } + + int frame_len = packet_len / d_syms_per_set; + int k = 0; + int i = frame_len * d_syms_per_set; + while (i < packet_len) { + frame_len++; + i += d_occupied_carriers[k].size(); + } + gr_tag_t tag; + tag.key = d_frame_len_tag_key; + tag.value = pmt::pmt_from_long(frame_len); + tags.push_back(tag); + + return true; + } + + } /* namespace digital */ +} /* namespace gr */ + diff --git a/gr-digital/lib/packet_headergenerator_bb_impl.cc b/gr-digital/lib/packet_headergenerator_bb_impl.cc new file mode 100644 index 0000000000..2698977728 --- /dev/null +++ b/gr-digital/lib/packet_headergenerator_bb_impl.cc @@ -0,0 +1,90 @@ +/* -*- c++ -*- */ +/* Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gr_io_signature.h> +#include "packet_headergenerator_bb_impl.h" + +namespace gr { + namespace digital { + + packet_headergenerator_bb::sptr + packet_headergenerator_bb::make(const packet_header_default::sptr &header_formatter) + { + return gnuradio::get_initial_sptr (new packet_headergenerator_bb_impl(header_formatter)); + } + + + packet_headergenerator_bb::sptr + packet_headergenerator_bb::make( + long header_len, + const std::string &len_tag_key + ) + { + const packet_header_default::sptr header_formatter( + new packet_header_default(header_len, len_tag_key) + ); + return gnuradio::get_initial_sptr (new packet_headergenerator_bb_impl(header_formatter)); + } + + + packet_headergenerator_bb_impl::packet_headergenerator_bb_impl( + const gr::digital::packet_header_default::sptr &header_formatter + ) + : gr_tagged_stream_block("packet_headergenerator_bb_impl", + gr_make_io_signature(1, 1, sizeof (char)), + gr_make_io_signature(1, 1, sizeof (char)), + pmt::pmt_symbol_to_string(header_formatter->len_tag_key())), + d_formatter(header_formatter), + d_input_size(1), + d_header_len(header_formatter->header_len()), + d_len_tag_value(pmt::pmt_from_long(d_header_len)) + { + set_output_multiple(d_header_len); + // This is the worst case rate, because we don't know the true value, of course + set_relative_rate(d_header_len); + set_tag_propagation_policy(TPP_DONT); + } + + packet_headergenerator_bb_impl::~packet_headergenerator_bb_impl() + { + } + + int + packet_headergenerator_bb_impl::work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + unsigned char *out = (unsigned char *) output_items[0]; + if (!d_formatter->header_formatter(ninput_items[0], out)) { + throw std::runtime_error("header formatter returned false."); + } + + return d_header_len; + } + + } /* namespace digital */ +} /* namespace gr */ + diff --git a/gr-digital/lib/packet_headergenerator_bb_impl.h b/gr-digital/lib/packet_headergenerator_bb_impl.h new file mode 100644 index 0000000000..7d2494cf8b --- /dev/null +++ b/gr-digital/lib/packet_headergenerator_bb_impl.h @@ -0,0 +1,55 @@ +/* -*- c++ -*- */ +/* Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DIGITAL_PACKET_HEADERGENERATOR_BB_IMPL_H +#define INCLUDED_DIGITAL_PACKET_HEADERGENERATOR_BB_IMPL_H + +#include <digital/packet_headergenerator_bb.h> + +namespace gr { + namespace digital { + + class packet_headergenerator_bb_impl : public packet_headergenerator_bb + { + private: + gr::digital::packet_header_default::sptr d_formatter; + int d_input_size; + int d_header_len; + pmt::pmt_t d_len_tag_value; + + public: + packet_headergenerator_bb_impl(const packet_header_default::sptr &header_formatter); + ~packet_headergenerator_bb_impl(); + + void remove_length_tags(const std::vector<std::vector<gr_tag_t> > &tags) {}; + int calculate_output_stream_length(const gr_vector_int &ninput_items) { return d_header_len; }; + + int work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } // namespace digital +} // namespace gr + +#endif /* INCLUDED_DIGITAL_PACKET_HEADERGENERATOR_BB_IMPL_H */ + diff --git a/gr-digital/lib/packet_headerparser_b_impl.cc b/gr-digital/lib/packet_headerparser_b_impl.cc new file mode 100644 index 0000000000..65883f5515 --- /dev/null +++ b/gr-digital/lib/packet_headerparser_b_impl.cc @@ -0,0 +1,90 @@ +/* -*- c++ -*- */ +/* Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gr_io_signature.h> +#include "packet_headerparser_b_impl.h" + +#define msg_port_id pmt::mp("header_data") + +namespace gr { + namespace digital { + + packet_headerparser_b::sptr + packet_headerparser_b::make(long header_len, const std::string &len_tag_key) + { + const packet_header_default::sptr header_formatter( + new packet_header_default(header_len, len_tag_key) + ); + return gnuradio::get_initial_sptr (new packet_headerparser_b_impl(header_formatter)); + } + + packet_headerparser_b::sptr + packet_headerparser_b::make(const gr::digital::packet_header_default::sptr &header_formatter) + { + return gnuradio::get_initial_sptr (new packet_headerparser_b_impl(header_formatter)); + } + + packet_headerparser_b_impl::packet_headerparser_b_impl(const gr::digital::packet_header_default::sptr &header_formatter) + : gr_sync_block("packet_headerparser_b", + gr_make_io_signature(1, 1, sizeof (unsigned char)), + gr_make_io_signature(0, 0, 0)), + d_header_formatter(header_formatter) + { + message_port_register_out(msg_port_id); + set_output_multiple(header_formatter->header_len()); + } + + packet_headerparser_b_impl::~packet_headerparser_b_impl() + { + } + + int + packet_headerparser_b_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const unsigned char *in = (const unsigned char *) input_items[0]; + + if (noutput_items < d_header_formatter->header_len()) { + return 0; + } + + std::vector<gr_tag_t> tags; + if (!d_header_formatter->header_parser(in, tags)) { + message_port_pub(msg_port_id, pmt::PMT_F); + } else { + pmt::pmt_t dict(pmt::pmt_make_dict()); + for (unsigned i = 0; i < tags.size(); i++) { + pmt::pmt_dict_add(dict, tags[i].key, tags[i].value); + } + message_port_pub(msg_port_id, dict); + } + + return d_header_formatter->header_len(); + } + + } /* namespace digital */ +} /* namespace gr */ + diff --git a/gr-digital/lib/packet_headerparser_b_impl.h b/gr-digital/lib/packet_headerparser_b_impl.h new file mode 100644 index 0000000000..a7ded1143f --- /dev/null +++ b/gr-digital/lib/packet_headerparser_b_impl.h @@ -0,0 +1,48 @@ +/* -*- c++ -*- */ +/* Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DIGITAL_PACKET_HEADERPARSER_B_IMPL_H +#define INCLUDED_DIGITAL_PACKET_HEADERPARSER_B_IMPL_H + +#include <digital/packet_headerparser_b.h> + +namespace gr { + namespace digital { + + class packet_headerparser_b_impl : public packet_headerparser_b + { + private: + packet_header_default::sptr d_header_formatter; + + public: + packet_headerparser_b_impl(const gr::digital::packet_header_default::sptr &header_formatter); + ~packet_headerparser_b_impl(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } // namespace digital +} // namespace gr + +#endif /* INCLUDED_DIGITAL_PACKET_HEADERPARSER_B_IMPL_H */ + diff --git a/gr-digital/lib/scale_tags_impl.cc b/gr-digital/lib/scale_tags_impl.cc new file mode 100644 index 0000000000..05c4635f74 --- /dev/null +++ b/gr-digital/lib/scale_tags_impl.cc @@ -0,0 +1,84 @@ +/* -*- c++ -*- */ +/* Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gr_io_signature.h> +#include "scale_tags_impl.h" + +namespace gr { + namespace digital { + + scale_tags::sptr + scale_tags::make(size_t itemsize, const std::string& tagname, float scale_factor) + { + return gnuradio::get_initial_sptr (new scale_tags_impl(itemsize, tagname, scale_factor)); + } + + /* + * The private constructor + */ + scale_tags_impl::scale_tags_impl(size_t itemsize, const std::string& tagname, float scale_factor) + : gr_sync_block("scale_tags", + gr_make_io_signature(1, 1, itemsize), + gr_make_io_signature(1, 1, itemsize)), + d_itemsize(itemsize), + d_tagname(tagname), + d_scale_factor(scale_factor) + { + set_tag_propagation_policy(TPP_DONT); + } + + /* + * Our virtual destructor. + */ + scale_tags_impl::~scale_tags_impl() + { + } + + int + scale_tags_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + const char *in = (const char *) input_items[0]; + char *out = (char *) output_items[0]; + std::vector<gr_tag_t> tags; + this->get_tags_in_range(tags, 0, nitems_read(0), nitems_read(0)+noutput_items); + //const size_t ninput_items = noutput_items; //assumption for sync block, this can change + for (unsigned int j = 0; j < tags.size(); j++) { + long value = pmt::pmt_to_long(tags[j].value); + if (pmt::pmt_symbol_to_string(tags[j].key) == d_tagname) { + value = long(value*d_scale_factor); + } + this->add_item_tag(0, tags[j].offset, tags[j].key, pmt::pmt_from_long(value)); + } + memcpy((void *) out, (const void *) in, noutput_items*d_itemsize); + + // Tell runtime system how many output items we produced. + return noutput_items; + } + + } /* namespace digital */ +} /* namespace gr */ + diff --git a/gr-digital/lib/scale_tags_impl.h b/gr-digital/lib/scale_tags_impl.h new file mode 100644 index 0000000000..667cda36eb --- /dev/null +++ b/gr-digital/lib/scale_tags_impl.h @@ -0,0 +1,51 @@ +/* -*- c++ -*- */ +/* Copyright 2012 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DIGITAL_SCALE_TAGS_IMPL_H +#define INCLUDED_DIGITAL_SCALE_TAGS_IMPL_H + +#include <digital/scale_tags.h> + +namespace gr { + namespace digital { + + class scale_tags_impl : public scale_tags + { + private: + size_t d_itemsize; + std::string d_tagname; + float d_scale_factor; + + public: + scale_tags_impl(size_t itemsize, const std::string&, float scale_factor); + ~scale_tags_impl(); + + // Where all the action really happens + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + }; + + } // namespace digital +} // namespace gr + +#endif /* INCLUDED_DIGITAL_SCALE_TAGS_IMPL_H */ + diff --git a/gr-digital/lib/tagged_stream_check_impl.cc b/gr-digital/lib/tagged_stream_check_impl.cc new file mode 100644 index 0000000000..732493f0ec --- /dev/null +++ b/gr-digital/lib/tagged_stream_check_impl.cc @@ -0,0 +1,112 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 <+YOU OR YOUR COMPANY+>. + * + * This 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, or (at your option) + * any later version. + * + * This software 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 software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gr_io_signature.h> +#include "tagged_stream_check_impl.h" +#include <iostream> +#include <vector> +#include <algorithm> +#include <string> +#include <sstream> + +namespace gr { + namespace digital { + + bool sort_tag_by_offset(gr_tag_t const & L, gr_tag_t const & R) { + return L.offset < R.offset; + } + + tagged_stream_check::sptr + tagged_stream_check::make(size_t itemsize, const std::string &lengthtagname) + { + return gnuradio::get_initial_sptr (new tagged_stream_check_impl(itemsize, lengthtagname)); + } + + /* + * The private constructor + */ + tagged_stream_check_impl::tagged_stream_check_impl(size_t itemsize, const std::string &lengthtagname) + : gr_sync_block("tagged_stream_check", + gr_make_io_signature(1, 1, itemsize), + gr_make_io_signature(1, 1, itemsize)), + d_lengthtagname(lengthtagname), d_itemsize(itemsize) + { + d_expected_offset = 0; + d_last_offset = 0; + } + + /* + * Our virtual destructor. + */ + tagged_stream_check_impl::~tagged_stream_check_impl() + { + } + + int + tagged_stream_check_impl::work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + char *out = (char *) output_items[0]; + const char *in = (const char*) input_items[0]; + // Find all the length tags + std::vector<gr_tag_t> tags; + std::vector<gr_tag_t> lengthtags; + this->get_tags_in_range(tags, 0, nitems_read(0), nitems_read(0)+noutput_items); + for (unsigned int j = 0; j < tags.size(); j++) { + if (pmt::pmt_symbol_to_string(tags[j].key) == d_lengthtagname) { + lengthtags.push_back(tags[j]); + } + } + // If there are no lengthtags then check that we weren't expecting one. + if (lengthtags.size() == 0) { + if (d_expected_offset < nitems_read(0)+noutput_items) { + std::ostringstream ss; + ss << "ERROR: "<<this->unique_id()<<" Expected a lengthtag at offset="<<d_expected_offset<<" but didn't find it"; + std::cout << ss.str() << std::endl; + } + } + // Sort them and make sure the lengthtags are in the proper places. + sort(lengthtags.begin(), lengthtags.end(), sort_tag_by_offset); + for (unsigned int j = 0; j < lengthtags.size(); j++) { + if (lengthtags[j].offset != d_expected_offset) { + std::cout << "****************************" << std::endl; + std::cout << "ERROR: "<<this->unique_id()<<" offset: " << lengthtags[j].offset << " The last tag had a length of " << d_expected_offset - d_last_offset << " but we got a length of " << lengthtags[j].offset - d_last_offset << std::endl; + } + long packet_length = pmt::pmt_to_long(lengthtags[j].value); + std::cout << "INFO: "<<this->unique_id()<<" offset: " << lengthtags[j].offset << std::endl; + d_expected_offset = lengthtags[j].offset + packet_length; + d_last_offset = lengthtags[j].offset; + } + memcpy((void *) out, (const void *) in, noutput_items*d_itemsize); + std::ostringstream ss; + ss << "checker: Produced data from " << nitems_read(0) << " to " << nitems_read(0) + noutput_items; + std::cout << ss.str() << std::endl; + return noutput_items; + } + + + } /* namespace digital */ +} /* namespace gr */ + diff --git a/gr-digital/lib/tagged_stream_check_impl.h b/gr-digital/lib/tagged_stream_check_impl.h new file mode 100644 index 0000000000..0b0dfe5b1a --- /dev/null +++ b/gr-digital/lib/tagged_stream_check_impl.h @@ -0,0 +1,53 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 <+YOU OR YOUR COMPANY+>. + * + * This 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, or (at your option) + * any later version. + * + * This software 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 software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DIGITAL_TAGGED_STREAM_CHECK_IMPL_H +#define INCLUDED_DIGITAL_TAGGED_STREAM_CHECK_IMPL_H + +#include <digital/tagged_stream_check.h> +#include <vector> + +namespace gr { + namespace digital { + + class tagged_stream_check_impl : public tagged_stream_check + { + private: + const std::string d_lengthtagname; + size_t d_itemsize; + uint64_t d_expected_offset; + uint64_t d_last_offset; + + public: + tagged_stream_check_impl(size_t itemsize, const std::string &lengthtagname); + ~tagged_stream_check_impl(); + + // Where all the action really happens + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + }; + + } // namespace digital +} // namespace gr + +#endif + diff --git a/gr-digital/lib/ts_insert_zeros_cc_impl.cc b/gr-digital/lib/ts_insert_zeros_cc_impl.cc new file mode 100644 index 0000000000..6c40a81f86 --- /dev/null +++ b/gr-digital/lib/ts_insert_zeros_cc_impl.cc @@ -0,0 +1,130 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 <+YOU OR YOUR COMPANY+>. + * + * This 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, or (at your option) + * any later version. + * + * This software 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 software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gr_io_signature.h> +#include "ts_insert_zeros_cc_impl.h" +#include <iostream> +#include <vector> +#include <algorithm> +#include <string> +#include <sstream> + +namespace gr { + namespace digital { + + ts_insert_zeros_cc::sptr + ts_insert_zeros_cc::make(const std::string &lengthtagname) + { + return gnuradio::get_initial_sptr (new ts_insert_zeros_cc_impl(lengthtagname)); + } + + /* + * The private constructor + */ + ts_insert_zeros_cc_impl::ts_insert_zeros_cc_impl(const std::string &lengthtagname) + : gr_block("ts_insert_zeros_cc", + gr_make_io_signature(1, 1, sizeof(gr_complex)), + gr_make_io_signature(1, 1, sizeof(gr_complex))), + d_lengthtagname(lengthtagname) + { + } + + /* + * Our virtual destructor. + */ + ts_insert_zeros_cc_impl::~ts_insert_zeros_cc_impl() + { + } + + void + ts_insert_zeros_cc_impl::forecast(int noutput_items, gr_vector_int &ninput_items_required) + { + ninput_items_required[0] = 0; + } + + int + ts_insert_zeros_cc_impl::general_work ( + int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items + ) + { + gr_complex *out = (gr_complex *) output_items[0]; + const gr_complex*in = (const gr_complex*) input_items[0]; + + if (ninput_items[0]) { + // Check if we have an entire packet. + long packet_length = 0; + std::vector<gr_tag_t> tags; + // Get any tags associated with the first item on the input. + this->get_tags_in_range(tags, 0, nitems_read(0), nitems_read(0)+1); + for (unsigned int j = 0; j < tags.size(); j++) { + if (pmt::pmt_symbol_to_string(tags[j].key) == d_lengthtagname) { + packet_length = pmt::pmt_to_long(tags[j].value); + } + } + if (!packet_length) { + throw std::runtime_error("no tag"); + } + if (ninput_items[0] < packet_length ) { + // We don't have enough input to produce a packet. + // Produces zeros instead. + } else { + // We have enough input. + if (noutput_items < packet_length) { + // But we don't have enough output space. + // We don't want to produce zeros, so return. + set_output_multiple(packet_length); + return 0; + } else { + // And we have enough output space. + // Produce the packet. + std::vector<gr_tag_t> tags; + this->get_tags_in_range(tags, 0, nitems_read(0), nitems_read(0)+packet_length); + for (unsigned int j = 0; j < tags.size(); j++) { + const uint64_t offset = tags[j].offset - nitems_read(0) + nitems_written(0); + this->add_item_tag(0, offset, tags[j].key, tags[j].value); + } + if (noutput_items < packet_length) { + throw std::runtime_error("Not enough room in the output buffer."); + } + memcpy(out, in, packet_length*sizeof(gr_complex)); + consume(0, packet_length); + return packet_length; + } + } + } + // We're just producing zeros. + // Either we have no input data, or not an entire packet yet. + for (int i=0; i<noutput_items; i++) { + out[i] = 0; + } + return noutput_items; + } + + + } /* namespace digital */ +} /* namespace gr */ + diff --git a/gr-digital/lib/ts_insert_zeros_cc_impl.h b/gr-digital/lib/ts_insert_zeros_cc_impl.h new file mode 100644 index 0000000000..4bdfbfe9fd --- /dev/null +++ b/gr-digital/lib/ts_insert_zeros_cc_impl.h @@ -0,0 +1,54 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 <+YOU OR YOUR COMPANY+>. + * + * This 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, or (at your option) + * any later version. + * + * This software 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 software; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_DIGITAL_TS_INSERT_ZEROS_CC_IMPL_H +#define INCLUDED_DIGITAL_TS_INSERT_ZEROS_CC_IMPL_H + +#include <digital/ts_insert_zeros_cc.h> +#include <vector> + +namespace gr { + namespace digital { + + class ts_insert_zeros_cc_impl : public ts_insert_zeros_cc + { + private: + const std::string d_lengthtagname; + + public: + ts_insert_zeros_cc_impl(const std::string &lengthtagname); + ~ts_insert_zeros_cc_impl(); + + void forecast(int noutput_items, gr_vector_int &ninput_items_required); + + // Where all the action really happens + int general_work( + int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items + ); + }; + + } // namespace digital +} // namespace gr + +#endif + |