/* -*- c++ -*- */ /* * Copyright 2014 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 <gnuradio/io_signature.h> #include "atsc_viterbi_decoder_impl.h" #include "atsc_types.h" #include "atsc_viterbi_mux.h" namespace gr { namespace dtv { atsc_viterbi_decoder::sptr atsc_viterbi_decoder::make() { return gnuradio::get_initial_sptr (new atsc_viterbi_decoder_impl()); } atsc_viterbi_decoder_impl::atsc_viterbi_decoder_impl() : sync_block("dtv_atsc_viterbi_decoder", io_signature::make(1, 1, sizeof(atsc_soft_data_segment)), io_signature::make(1, 1, sizeof(atsc_mpeg_packet_rs_encoded))) { set_output_multiple(NCODERS); /* * These fifo's handle the alignment problem caused by the * inherent decoding delay of the individual viterbi decoders. * The net result is that this entire block has a pipeline latency * of 12 complete segments. * * If anybody cares, it is possible to do it with less delay, but * this approach is at least somewhat understandable... */ // the -4 is for the 4 sync symbols int fifo_size = ATSC_DATA_SEGMENT_LENGTH - 4 - viterbi[0].delay(); for (int i = 0; i < NCODERS; i++) fifo[i] = new fifo_t(fifo_size); reset(); } atsc_viterbi_decoder_impl::~atsc_viterbi_decoder_impl() { for (int i = 0; i < NCODERS; i++) delete fifo[i]; } void atsc_viterbi_decoder_impl::reset() { for (int i = 0; i < NCODERS; i++) fifo[i]->reset(); } std::vector<float> atsc_viterbi_decoder_impl::decoder_metrics() const { std::vector<float> metrics(NCODERS); for (int i = 0; i < NCODERS; i++) metrics[i] = viterbi[i].best_state_metric(); return metrics; } int atsc_viterbi_decoder_impl::work(int noutput_items, gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { const atsc_soft_data_segment *in = (const atsc_soft_data_segment *) input_items[0]; atsc_mpeg_packet_rs_encoded *out = (atsc_mpeg_packet_rs_encoded *) output_items[0]; // The way the fs_checker works ensures we start getting packets // starting with a field sync, and out input multiple is set to // 12, so we should always get a mod 12 numbered first packet assert(noutput_items % NCODERS == 0); int dbwhere; int dbindex; int shift; float symbols[NCODERS][enco_which_max]; unsigned char dibits[NCODERS][enco_which_max]; unsigned char out_copy[OUTPUT_SIZE]; for (int i = 0; i < noutput_items; i += NCODERS) { /* Build a continuous symbol buffer for each encoder */ for (unsigned int encoder = 0; encoder < NCODERS; encoder++) for (unsigned int k = 0; k < enco_which_max; k++) symbols[encoder][k] = in[i + (enco_which_syms[encoder][k]/832)].data[enco_which_syms[encoder][k] % 832]; /* Now run each of the 12 Viterbi decoders over their subset of the input symbols */ for (unsigned int encoder = 0; encoder < NCODERS; encoder++) for (unsigned int k = 0; k < enco_which_max; k++) dibits[encoder][k] = viterbi[encoder].decode(symbols[encoder][k]); /* Move dibits into their location in the output buffer */ for (unsigned int encoder = 0; encoder < NCODERS; encoder++) { for (unsigned int k = 0; k < enco_which_max; k++) { /* Store the dibit into the output data segment */ dbwhere = enco_which_dibits[encoder][k]; dbindex = dbwhere >> 3; shift = dbwhere & 0x7; out_copy[dbindex] = (out_copy[dbindex] & ~(0x03 << shift)) | (fifo[encoder]->stuff(dibits[encoder][k]) << shift); } /* Symbols fed into one encoder */ } /* Encoders */ // copy output from contiguous temp buffer into final output for (int j = 0; j < NCODERS; j++) { memcpy (&out[i + j].data[0], &out_copy[j * OUTPUT_SIZE/NCODERS], ATSC_MPEG_RS_ENCODED_LENGTH * sizeof(out_copy[0])); // adjust pipeline info to reflect 12 segment delay plinfo::delay(out[i + j].pli, in[i + j].pli, NCODERS); } } return noutput_items; } void atsc_viterbi_decoder_impl::setup_rpc() { #ifdef GR_CTRLPORT add_rpc_variable( rpcbasic_sptr(new rpcbasic_register_get<atsc_viterbi_decoder, std::vector<float> >( alias(), "decoder_metrics", &atsc_viterbi_decoder::decoder_metrics, pmt::make_f32vector(1,0), pmt::make_f32vector(1,100000), pmt::make_f32vector(1,0), "", "Viterbi decoder metrics", RPC_PRIVLVL_MIN, DISPTIME))); #endif /* GR_CTRLPORT */ } } /* namespace dtv */ } /* namespace gr */