diff options
29 files changed, 464 insertions, 287 deletions
diff --git a/gr-dtv/grc/dtv_atsc_deinterleaver.block.yml b/gr-dtv/grc/dtv_atsc_deinterleaver.block.yml index fd838138b4..7628bc8bc2 100644 --- a/gr-dtv/grc/dtv_atsc_deinterleaver.block.yml +++ b/gr-dtv/grc/dtv_atsc_deinterleaver.block.yml @@ -5,12 +5,12 @@ flags: [ python, cpp ] inputs: - domain: stream dtype: byte - vlen: 256 + vlen: 207 outputs: - domain: stream dtype: byte - vlen: 256 + vlen: 207 templates: imports: from gnuradio import dtv diff --git a/gr-dtv/grc/dtv_atsc_depad.block.yml b/gr-dtv/grc/dtv_atsc_depad.block.yml index b44773ea13..65ae1722f6 100644 --- a/gr-dtv/grc/dtv_atsc_depad.block.yml +++ b/gr-dtv/grc/dtv_atsc_depad.block.yml @@ -5,7 +5,7 @@ flags: [ python, cpp ] inputs: - domain: stream dtype: byte - vlen: 256 + vlen: 188 outputs: - domain: stream diff --git a/gr-dtv/grc/dtv_atsc_derandomizer.block.yml b/gr-dtv/grc/dtv_atsc_derandomizer.block.yml index cf6f747030..3329965030 100644 --- a/gr-dtv/grc/dtv_atsc_derandomizer.block.yml +++ b/gr-dtv/grc/dtv_atsc_derandomizer.block.yml @@ -5,12 +5,12 @@ flags: [ python, cpp ] inputs: - domain: stream dtype: byte - vlen: 256 + vlen: 188 outputs: - domain: stream dtype: byte - vlen: 256 + vlen: 188 templates: imports: from gnuradio import dtv diff --git a/gr-dtv/grc/dtv_atsc_equalizer.block.yml b/gr-dtv/grc/dtv_atsc_equalizer.block.yml index dfc0d9c5d5..3d55d85af7 100644 --- a/gr-dtv/grc/dtv_atsc_equalizer.block.yml +++ b/gr-dtv/grc/dtv_atsc_equalizer.block.yml @@ -4,13 +4,13 @@ flags: [ python, cpp ] inputs: - domain: stream - dtype: byte - vlen: 4096 + dtype: float + vlen: 832 outputs: - domain: stream - dtype: byte - vlen: 4096 + dtype: float + vlen: 832 templates: imports: from gnuradio import dtv diff --git a/gr-dtv/grc/dtv_atsc_fs_checker.block.yml b/gr-dtv/grc/dtv_atsc_fs_checker.block.yml index 31053440ac..098a440382 100644 --- a/gr-dtv/grc/dtv_atsc_fs_checker.block.yml +++ b/gr-dtv/grc/dtv_atsc_fs_checker.block.yml @@ -4,13 +4,13 @@ flags: [ python, cpp ] inputs: - domain: stream - dtype: byte - vlen: 4096 + dtype: float + vlen: 832 outputs: - domain: stream - dtype: byte - vlen: 4096 + dtype: float + vlen: 832 templates: imports: from gnuradio import dtv diff --git a/gr-dtv/grc/dtv_atsc_rs_decoder.block.yml b/gr-dtv/grc/dtv_atsc_rs_decoder.block.yml index e04c91ec3b..08bb639339 100644 --- a/gr-dtv/grc/dtv_atsc_rs_decoder.block.yml +++ b/gr-dtv/grc/dtv_atsc_rs_decoder.block.yml @@ -5,12 +5,12 @@ flags: [ python, cpp ] inputs: - domain: stream dtype: byte - vlen: 256 + vlen: 207 outputs: - domain: stream dtype: byte - vlen: 256 + vlen: 188 templates: imports: from gnuradio import dtv diff --git a/gr-dtv/grc/dtv_atsc_sync.block.yml b/gr-dtv/grc/dtv_atsc_sync.block.yml index d1dfdf43d5..02cfc83ab9 100644 --- a/gr-dtv/grc/dtv_atsc_sync.block.yml +++ b/gr-dtv/grc/dtv_atsc_sync.block.yml @@ -13,8 +13,8 @@ inputs: outputs: - domain: stream - dtype: byte - vlen: 4096 + dtype: float + vlen: 832 templates: imports: from gnuradio import dtv diff --git a/gr-dtv/grc/dtv_atsc_viterbi_decoder.block.yml b/gr-dtv/grc/dtv_atsc_viterbi_decoder.block.yml index 0649dcd2ad..199560c925 100644 --- a/gr-dtv/grc/dtv_atsc_viterbi_decoder.block.yml +++ b/gr-dtv/grc/dtv_atsc_viterbi_decoder.block.yml @@ -4,13 +4,13 @@ flags: [ python, cpp ] inputs: - domain: stream - dtype: byte - vlen: 4096 + dtype: float + vlen: 832 outputs: - domain: stream dtype: byte - vlen: 256 + vlen: 207 templates: imports: from gnuradio import dtv diff --git a/gr-dtv/include/gnuradio/dtv/CMakeLists.txt b/gr-dtv/include/gnuradio/dtv/CMakeLists.txt index cc7ebf4690..9d328f9733 100644 --- a/gr-dtv/include/gnuradio/dtv/CMakeLists.txt +++ b/gr-dtv/include/gnuradio/dtv/CMakeLists.txt @@ -11,6 +11,7 @@ install(FILES api.h atsc_consts.h + atsc_plinfo.h atsc_deinterleaver.h atsc_depad.h atsc_derandomizer.h diff --git a/gr-dtv/include/gnuradio/dtv/atsc_plinfo.h b/gr-dtv/include/gnuradio/dtv/atsc_plinfo.h new file mode 100644 index 0000000000..4496ca8092 --- /dev/null +++ b/gr-dtv/include/gnuradio/dtv/atsc_plinfo.h @@ -0,0 +1,119 @@ +/* -*- c++ -*- */ +/* + * Copyright 2001,2006,2014 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#ifndef DTV_INCLUDED_ATSC_PLINFO_H +#define DTV_INCLUDED_ATSC_PLINFO_H + +#include <gnuradio/dtv/atsc_consts.h> +#include <boost/endian/conversion.hpp> +#include <cassert> +#include <cstring> + +#include <gnuradio/dtv/api.h> + +namespace gr { +namespace dtv { + +/*! + * \brief pipeline info that flows with data + * + * Not all modules need all the info + */ +class DTV_API plinfo +{ +public: + plinfo(); + plinfo(uint16_t flags, int16_t segno); + + /** + * @brief Resets the flags and segno fields + * + */ + void reset(); + + /** + * @brief Load the flags and segno from an endian safe value that came over the tags + * + * @param tag_value + */ + void from_tag_value(uint32_t tag_value); + + /** + * @brief Return an endian safe value containing the flags and segno + * + * @return uint32_t + */ + uint32_t get_tag_value() const; + + // accessors + bool field_sync1_p() const; + bool field_sync2_p() const; + bool field_sync_p() const; + + bool regular_seg_p() const; + + bool in_field1_p() const; + bool in_field2_p() const; + + bool first_regular_seg_p() const; + + bool transport_error_p() const; + + unsigned int segno() const; + unsigned int flags() const; + + // setters + + void set_field_sync1(); + + void set_field_sync2(); + + void set_regular_seg(bool field2, int segno); + + void set_transport_error(bool error); + + /*! + * Set \p OUT such that it reflects a \p NSEGS_OF_DELAY + * pipeline delay from \p IN. + */ + static void delay(plinfo& out, const plinfo& in, int nsegs_of_delay); + + // these three are mutually exclusive + // This is a regular data segment. + static constexpr int fl_regular_seg = 0x0001; + // This is a field sync segment, for 1st half of a field. + static constexpr int fl_field_sync1 = 0x0002; + // This is a field sync segment, for 2nd half of a field. + static constexpr int fl_field_sync2 = 0x0004; + + // This bit is on ONLY when fl_regular_seg is set AND when this is + // the first regular data segment AFTER a field sync segment. This + // segment causes various processing modules to reset. + static constexpr int fl_first_regular_seg = 0x0008; + + // which field are we in? + static constexpr int fl_field2 = 0x0010; // else field 1 + + // This bit is set when Reed-Solomon decoding detects an error that it + // can't correct. Note that other error detection (e.g. Viterbi) do not + // set it, since Reed-Solomon will correct many of those. This bit is + // then copied into the final Transport Stream packet so that MPEG + // software can see that the 188-byte data segment has been corrupted. + static constexpr int fl_transport_error = 0x0020; + +private: + uint16_t d_flags = 0; // bitmask + int16_t d_segno = 0; // segment number [-1,311] -1 is the field sync segment +}; + +} /* namespace dtv */ +} /* namespace gr */ + +#endif /* _ATSC_PLINFO_H_ */ diff --git a/gr-dtv/lib/CMakeLists.txt b/gr-dtv/lib/CMakeLists.txt index 7f26570e3a..18ca5539f4 100644 --- a/gr-dtv/lib/CMakeLists.txt +++ b/gr-dtv/lib/CMakeLists.txt @@ -9,6 +9,7 @@ # Setup library ######################################################################## add_library(gnuradio-dtv + atsc/atsc_plinfo.cc atsc/atsc_deinterleaver_impl.cc atsc/atsc_depad_impl.cc atsc/atsc_derandomizer_impl.cc diff --git a/gr-dtv/lib/atsc/atsc_deinterleaver_impl.cc b/gr-dtv/lib/atsc/atsc_deinterleaver_impl.cc index 616a4c2688..d83d0a625f 100644 --- a/gr-dtv/lib/atsc/atsc_deinterleaver_impl.cc +++ b/gr-dtv/lib/atsc/atsc_deinterleaver_impl.cc @@ -25,9 +25,10 @@ atsc_deinterleaver::sptr atsc_deinterleaver::make() } atsc_deinterleaver_impl::atsc_deinterleaver_impl() - : gr::sync_block("atsc_deinterleaver", - io_signature::make(1, 1, sizeof(atsc_mpeg_packet_rs_encoded)), - io_signature::make(1, 1, sizeof(atsc_mpeg_packet_rs_encoded))), + : gr::sync_block( + "atsc_deinterleaver", + io_signature::make(1, 1, ATSC_MPEG_RS_ENCODED_LENGTH * sizeof(uint8_t)), + io_signature::make(1, 1, ATSC_MPEG_RS_ENCODED_LENGTH * sizeof(uint8_t))), alignment_fifo(156) { m_fifo.reserve(s_interleavers); @@ -36,6 +37,8 @@ atsc_deinterleaver_impl::atsc_deinterleaver_impl() m_fifo.emplace_back((s_interleavers - 1 - i) * 4); sync(); + + set_tag_propagation_policy(TPP_CUSTOM); } atsc_deinterleaver_impl::~atsc_deinterleaver_impl() {} @@ -52,24 +55,38 @@ int atsc_deinterleaver_impl::work(int noutput_items, gr_vector_const_void_star& input_items, gr_vector_void_star& output_items) { - const atsc_mpeg_packet_rs_encoded* in = - (const atsc_mpeg_packet_rs_encoded*)input_items[0]; - atsc_mpeg_packet_rs_encoded* out = (atsc_mpeg_packet_rs_encoded*)output_items[0]; + auto in = static_cast<const uint8_t*>(input_items[0]); + auto out = static_cast<uint8_t*>(output_items[0]); + std::vector<tag_t> tags; + auto tag_pmt = pmt::intern("plinfo"); for (int i = 0; i < noutput_items; i++) { - assert(in[i].pli.regular_seg_p()); - plinfo::sanity_check(in[i].pli); + plinfo pli_in; + get_tags_in_window(tags, 0, i, i + 1, tag_pmt); + if (tags.size() > 0) { + pli_in.from_tag_value(pmt::to_uint64(tags[0].value)); + } else { + throw std::runtime_error( + "Atsc Deinterleaver: Plinfo Tag not found on sample"); + } + + assert(pli_in.regular_seg_p()); // reset commutator if required using INPUT pipeline info - if (in[i].pli.first_regular_seg_p()) + if (pli_in.first_regular_seg_p()) sync(); // remap OUTPUT pipeline info to reflect all data segment end-to-end delay - plinfo::delay(out[i].pli, in[i].pli, s_interleavers); + plinfo pli_out; + plinfo::delay(pli_out, pli_in, s_interleavers); + + add_item_tag( + 0, nitems_written(0) + i, tag_pmt, pmt::from_uint64(pli_out.get_tag_value())); // now do the actual deinterleaving - for (unsigned int j = 0; j < sizeof(in[i].data); j++) { - out[i].data[j] = alignment_fifo.stuff(transform(in[i].data[j])); + for (unsigned int j = 0; j < ATSC_MPEG_RS_ENCODED_LENGTH; j++) { + out[i * ATSC_MPEG_RS_ENCODED_LENGTH + j] = + alignment_fifo.stuff(transform(in[i * ATSC_MPEG_RS_ENCODED_LENGTH + j])); } } diff --git a/gr-dtv/lib/atsc/atsc_depad_impl.cc b/gr-dtv/lib/atsc/atsc_depad_impl.cc index a6d87a7362..246264fc6c 100644 --- a/gr-dtv/lib/atsc/atsc_depad_impl.cc +++ b/gr-dtv/lib/atsc/atsc_depad_impl.cc @@ -25,10 +25,11 @@ atsc_depad::sptr atsc_depad::make() } atsc_depad_impl::atsc_depad_impl() - : gr::sync_interpolator("atsc_depad", - io_signature::make(1, 1, sizeof(atsc_mpeg_packet)), - io_signature::make(1, 1, sizeof(unsigned char)), - ATSC_MPEG_PKT_LENGTH) + : gr::sync_interpolator( + "atsc_depad", + io_signature::make(1, 1, ATSC_MPEG_PKT_LENGTH * sizeof(uint8_t)), + io_signature::make(1, 1, sizeof(uint8_t)), + ATSC_MPEG_PKT_LENGTH) { } @@ -36,13 +37,15 @@ int atsc_depad_impl::work(int noutput_items, gr_vector_const_void_star& input_items, gr_vector_void_star& output_items) { - const atsc_mpeg_packet* in = (const atsc_mpeg_packet*)input_items[0]; - unsigned char* out = (unsigned char*)output_items[0]; + auto in = static_cast<const uint8_t*>(input_items[0]); + auto out = static_cast<uint8_t*>(output_items[0]); int i; for (i = 0; i < noutput_items / ATSC_MPEG_PKT_LENGTH; i++) - memcpy(&out[i * ATSC_MPEG_PKT_LENGTH], in[i].data, ATSC_MPEG_PKT_LENGTH); + memcpy(&out[i * ATSC_MPEG_PKT_LENGTH], + &in[i * ATSC_MPEG_PKT_LENGTH], + ATSC_MPEG_PKT_LENGTH); return i * ATSC_MPEG_PKT_LENGTH; } diff --git a/gr-dtv/lib/atsc/atsc_derandomizer_impl.cc b/gr-dtv/lib/atsc/atsc_derandomizer_impl.cc index 2b102838f0..33dcf47600 100644 --- a/gr-dtv/lib/atsc/atsc_derandomizer_impl.cc +++ b/gr-dtv/lib/atsc/atsc_derandomizer_impl.cc @@ -26,35 +26,44 @@ atsc_derandomizer::sptr atsc_derandomizer::make() atsc_derandomizer_impl::atsc_derandomizer_impl() : gr::sync_block("dtv_atsc_derandomizer", - io_signature::make(1, 1, sizeof(atsc_mpeg_packet_no_sync)), - io_signature::make(1, 1, sizeof(atsc_mpeg_packet))) + io_signature::make(1, 1, ATSC_MPEG_PKT_LENGTH * sizeof(uint8_t)), + io_signature::make(1, 1, ATSC_MPEG_PKT_LENGTH * sizeof(uint8_t))) { d_rand.reset(); + set_tag_propagation_policy(TPP_DONT); } int atsc_derandomizer_impl::work(int noutput_items, gr_vector_const_void_star& input_items, gr_vector_void_star& output_items) { - const atsc_mpeg_packet_no_sync* in = (const atsc_mpeg_packet_no_sync*)input_items[0]; - atsc_mpeg_packet* out = (atsc_mpeg_packet*)output_items[0]; + auto in = static_cast<const uint8_t*>(input_items[0]); + auto out = static_cast<uint8_t*>(output_items[0]); + std::vector<tag_t> tags; + auto tag_pmt = pmt::intern("plinfo"); for (int i = 0; i < noutput_items; i++) { + plinfo pli_in; + get_tags_in_window(tags, 0, i, i + 1, tag_pmt); + if (tags.size() > 0) { + pli_in.from_tag_value(pmt::to_uint64(tags[0].value)); + } else { + throw std::runtime_error("Atsc Derandomizer: Plinfo Tag not found on sample"); + } + assert(pli_in.regular_seg_p()); - assert(in[i].pli.regular_seg_p()); - - if (in[i].pli.first_regular_seg_p()) + if (pli_in.first_regular_seg_p()) d_rand.reset(); - d_rand.derandomize(out[i], in[i]); + d_rand.derandomize(&out[i * ATSC_MPEG_PKT_LENGTH], &in[i * ATSC_MPEG_PKT_LENGTH]); // Check the pipeline info for error status and and set the // corresponding bit in transport packet header. - if (in[i].pli.transport_error_p()) - out[i].data[1] |= MPEG_TRANSPORT_ERROR_BIT; + if (pli_in.transport_error_p()) + out[i * ATSC_MPEG_PKT_LENGTH + 1] |= MPEG_TRANSPORT_ERROR_BIT; else - out[i].data[1] &= ~MPEG_TRANSPORT_ERROR_BIT; + out[i * ATSC_MPEG_PKT_LENGTH + 1] &= ~MPEG_TRANSPORT_ERROR_BIT; } return noutput_items; diff --git a/gr-dtv/lib/atsc/atsc_equalizer_impl.cc b/gr-dtv/lib/atsc/atsc_equalizer_impl.cc index 6c701d607b..5970fb5d63 100644 --- a/gr-dtv/lib/atsc/atsc_equalizer_impl.cc +++ b/gr-dtv/lib/atsc/atsc_equalizer_impl.cc @@ -52,8 +52,8 @@ static void init_field_sync_common(float* p, int mask) atsc_equalizer_impl::atsc_equalizer_impl() : gr::block("dtv_atsc_equalizer", - io_signature::make(1, 1, sizeof(atsc_soft_data_segment)), - io_signature::make(1, 1, sizeof(atsc_soft_data_segment))) + io_signature::make(1, 1, ATSC_DATA_SEGMENT_LENGTH * sizeof(float)), + io_signature::make(1, 1, ATSC_DATA_SEGMENT_LENGTH * sizeof(float))) { init_field_sync_common(training_sequence1, 0); init_field_sync_common(training_sequence2, 1); @@ -64,6 +64,8 @@ atsc_equalizer_impl::atsc_equalizer_impl() const int alignment_multiple = volk_get_alignment() / sizeof(float); set_alignment(std::max(1, alignment_multiple)); + + set_tag_propagation_policy(TPP_CUSTOM); // use manual tag propagation } atsc_equalizer_impl::~atsc_equalizer_impl() {} @@ -114,17 +116,30 @@ int atsc_equalizer_impl::general_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_soft_data_segment* out = (atsc_soft_data_segment*)output_items[0]; + auto in = static_cast<const float*>(input_items[0]); + auto out = static_cast<float*>(output_items[0]); int output_produced = 0; int i = 0; + std::vector<tag_t> tags; + auto tag_pmt = pmt::intern("plinfo"); + + plinfo pli_in; if (d_buff_not_filled) { memset(&data_mem[0], 0, NPRETAPS * sizeof(float)); - memcpy(&data_mem[NPRETAPS], in[i].data, ATSC_DATA_SEGMENT_LENGTH * sizeof(float)); - d_flags = in[i].pli._flags; - d_segno = in[i].pli._segno; + memcpy(&data_mem[NPRETAPS], + in + i * ATSC_DATA_SEGMENT_LENGTH, + ATSC_DATA_SEGMENT_LENGTH * sizeof(float)); + get_tags_in_window(tags, 0, 0, 1, tag_pmt); + if (tags.size() > 0) { + pli_in.from_tag_value(pmt::to_uint64(tags[0].value)); + d_flags = pli_in.flags(); + d_segno = pli_in.segno(); + } else { + throw std::runtime_error("Atsc Equalizer: Plinfo Tag not found on sample"); + } + d_buff_not_filled = false; i++; } @@ -132,36 +147,44 @@ int atsc_equalizer_impl::general_work(int noutput_items, for (; i < noutput_items; i++) { memcpy(&data_mem[ATSC_DATA_SEGMENT_LENGTH + NPRETAPS], - in[i].data, + in + i * ATSC_DATA_SEGMENT_LENGTH, (NTAPS - NPRETAPS) * sizeof(float)); if (d_segno == -1) { if (d_flags & 0x0010) { adaptN(data_mem, training_sequence2, data_mem2, KNOWN_FIELD_SYNC_LENGTH); - // filterN(&data_mem[KNOWN_FIELD_SYNC_LENGTH], data_mem2, - // ATSC_DATA_SEGMENT_LENGTH - KNOWN_FIELD_SYNC_LENGTH); } else if (!(d_flags & 0x0010)) { adaptN(data_mem, training_sequence1, data_mem2, KNOWN_FIELD_SYNC_LENGTH); - // filterN(&data_mem[KNOWN_FIELD_SYNC_LENGTH], data_mem2, - // ATSC_DATA_SEGMENT_LENGTH - KNOWN_FIELD_SYNC_LENGTH); } } else { filterN(data_mem, data_mem2, ATSC_DATA_SEGMENT_LENGTH); - memcpy(out[output_produced].data, + memcpy(&out[output_produced * ATSC_DATA_SEGMENT_LENGTH], data_mem2, ATSC_DATA_SEGMENT_LENGTH * sizeof(float)); - out[output_produced].pli._flags = d_flags; - out[output_produced].pli._segno = d_segno; + plinfo pli_out(d_flags, d_segno); + add_item_tag(0, + nitems_written(0) + output_produced, + tag_pmt, + pmt::from_uint64(pli_out.get_tag_value())); + output_produced++; } memcpy(data_mem, &data_mem[ATSC_DATA_SEGMENT_LENGTH], NPRETAPS * sizeof(float)); - memcpy(&data_mem[NPRETAPS], in[i].data, ATSC_DATA_SEGMENT_LENGTH * sizeof(float)); - - d_flags = in[i].pli._flags; - d_segno = in[i].pli._segno; + memcpy(&data_mem[NPRETAPS], + in + i * ATSC_DATA_SEGMENT_LENGTH, + ATSC_DATA_SEGMENT_LENGTH * sizeof(float)); + + get_tags_in_window(tags, 0, i, i + 1, tag_pmt); + if (tags.size() > 0) { + pli_in.from_tag_value(pmt::to_uint64(tags[0].value)); + d_flags = pli_in.flags(); + d_segno = pli_in.segno(); + } else { + throw std::runtime_error("Atsc Equalizer: Plinfo Tag not found on sample"); + } } consume_each(noutput_items); diff --git a/gr-dtv/lib/atsc/atsc_field_sync_mux_impl.cc b/gr-dtv/lib/atsc/atsc_field_sync_mux_impl.cc index 0e778a983d..3e505eac9a 100644 --- a/gr-dtv/lib/atsc/atsc_field_sync_mux_impl.cc +++ b/gr-dtv/lib/atsc/atsc_field_sync_mux_impl.cc @@ -164,8 +164,7 @@ int atsc_field_sync_mux_impl::general_work(int noutput_items, // write out field sync... atsc_data_segment field_sync; - field_sync.pli._flags = 0; - field_sync.pli._segno = 0; + field_sync.pli.reset(); memset(field_sync._pad_, 0, atsc_data_segment::NPAD); if (in[index].pli.in_field1_p()) { diff --git a/gr-dtv/lib/atsc/atsc_fpll_impl.cc b/gr-dtv/lib/atsc/atsc_fpll_impl.cc index 0904d1aad0..0a133eb429 100644 --- a/gr-dtv/lib/atsc/atsc_fpll_impl.cc +++ b/gr-dtv/lib/atsc/atsc_fpll_impl.cc @@ -44,8 +44,9 @@ int atsc_fpll_impl::work(int noutput_items, constexpr float alpha = 0.01; constexpr float beta = alpha * alpha / 4.0; - const gr_complex* in = (const gr_complex*)input_items[0]; - float* out = (float*)output_items[0]; + auto in = static_cast<const gr_complex*>(input_items[0]); + auto out = static_cast<float*>(output_items[0]); + float a_cos, a_sin; float x; gr_complex result, filtered; diff --git a/gr-dtv/lib/atsc/atsc_fs_checker_impl.cc b/gr-dtv/lib/atsc/atsc_fs_checker_impl.cc index dd76277be9..cf00be36ee 100644 --- a/gr-dtv/lib/atsc/atsc_fs_checker_impl.cc +++ b/gr-dtv/lib/atsc/atsc_fs_checker_impl.cc @@ -35,8 +35,8 @@ atsc_fs_checker::sptr atsc_fs_checker::make() atsc_fs_checker_impl::atsc_fs_checker_impl() : gr::block("dtv_atsc_fs_checker", - io_signature::make(1, 1, sizeof(atsc_soft_data_segment)), - io_signature::make(1, 1, sizeof(atsc_soft_data_segment))) + io_signature::make(1, 1, ATSC_DATA_SEGMENT_LENGTH * sizeof(float)), + io_signature::make(1, 1, ATSC_DATA_SEGMENT_LENGTH * sizeof(float))) { gr::configure_default_loggers(d_logger, d_debug_logger, "dtv_atsc_fs_checker"); reset(); @@ -59,17 +59,20 @@ int atsc_fs_checker_impl::general_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_soft_data_segment* out = (atsc_soft_data_segment*)output_items[0]; + const float* in = static_cast<const float*>(input_items[0]); + float* out = static_cast<float*>(output_items[0]); int output_produced = 0; + auto tag_pmt = pmt::intern("plinfo"); + for (int i = 0; i < noutput_items; i++) { // check for a hit on the PN 511 pattern int errors = 0; for (int j = 0; j < LENGTH_511 && errors < PN511_ERROR_LIMIT; j++) - errors += (in[i].data[j + OFFSET_511] >= 0) ^ atsc_pn511[j]; + errors += + (in[i * ATSC_DATA_SEGMENT_LENGTH + j + OFFSET_511] >= 0) ^ atsc_pn511[j]; GR_LOG_DEBUG(d_debug_logger, std::string("second PN63 error count = ") + std::to_string(errors)); @@ -78,7 +81,8 @@ int atsc_fs_checker_impl::general_work(int noutput_items, // determine if this is field 1 or field 2 errors = 0; for (int j = 0; j < LENGTH_2ND_63; j++) - errors += (in[i].data[j + OFFSET_2ND_63] >= 0) ^ atsc_pn63[j]; + errors += (in[i * ATSC_DATA_SEGMENT_LENGTH + j + OFFSET_2ND_63] >= 0) ^ + atsc_pn63[j]; // we should have either field 1 (== PN63) or field 2 (== ~PN63) if (errors <= PN63_ERROR_LIMIT) { @@ -98,14 +102,23 @@ int atsc_fs_checker_impl::general_work(int noutput_items, if (d_field_num == 1 || d_field_num == 2) { // If we have sync // So we copy out current packet data to an output packet and fill its plinfo - for (int j = 0; j < ATSC_DATA_SEGMENT_LENGTH; j++) - out[output_produced].data[j] = in[i].data[j]; - out[output_produced].pli.set_regular_seg((d_field_num == 2), d_segment_num); + memcpy(&out[output_produced * ATSC_DATA_SEGMENT_LENGTH], + &in[i * ATSC_DATA_SEGMENT_LENGTH], + ATSC_DATA_SEGMENT_LENGTH * sizeof(float)); + + plinfo pli_out; + pli_out.set_regular_seg((d_field_num == 2), d_segment_num); + d_segment_num++; if (d_segment_num > (ATSC_SEGMENTS_PER_DATA_FIELD - 1)) { d_field_num = 0; d_segment_num = 0; } else { + add_item_tag(0, + nitems_written(0) + output_produced, + tag_pmt, + pmt::from_uint64(pli_out.get_tag_value())); + output_produced++; } } diff --git a/gr-dtv/lib/atsc/atsc_fs_checker_impl.h b/gr-dtv/lib/atsc/atsc_fs_checker_impl.h index 603b3d02e4..e0727273a4 100644 --- a/gr-dtv/lib/atsc/atsc_fs_checker_impl.h +++ b/gr-dtv/lib/atsc/atsc_fs_checker_impl.h @@ -13,7 +13,6 @@ #include "atsc_syminfo_impl.h" #include <gnuradio/dtv/atsc_fs_checker.h> -#include <gnuradio/logger.h> namespace gr { namespace dtv { @@ -28,8 +27,6 @@ private: unsigned char d_bit_sr[SRSIZE]; // binary decision shift register int d_field_num; int d_segment_num; - gr::logger_ptr d_logger; - gr::logger_ptr d_debug_logger; static constexpr int OFFSET_511 = 4; // offset to second PN 63 pattern static constexpr int LENGTH_511 = 511; // length of PN 63 pattern diff --git a/gr-dtv/lib/atsc/atsc_interleaver_impl.cc b/gr-dtv/lib/atsc/atsc_interleaver_impl.cc index 07b748029a..51a9e7ab3e 100644 --- a/gr-dtv/lib/atsc/atsc_interleaver_impl.cc +++ b/gr-dtv/lib/atsc/atsc_interleaver_impl.cc @@ -64,7 +64,6 @@ int atsc_interleaver_impl::work(int noutput_items, for (int i = 0; i < noutput_items; i++) { assert(in[i].pli.regular_seg_p()); - plinfo::sanity_check(in[i].pli); out[i].pli = in[i].pli; // copy pipeline info if (in[i].pli.first_regular_seg_p()) { // reset commutator if required diff --git a/gr-dtv/lib/atsc/atsc_plinfo.cc b/gr-dtv/lib/atsc/atsc_plinfo.cc new file mode 100644 index 0000000000..3f14b0c782 --- /dev/null +++ b/gr-dtv/lib/atsc/atsc_plinfo.cc @@ -0,0 +1,109 @@ +/* -*- c++ -*- */ +/* + * Copyright 2001,2006,2014 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include <gnuradio/dtv/atsc_plinfo.h> + +namespace gr { +namespace dtv { + +plinfo::plinfo() : d_flags(0), d_segno(0){}; +plinfo::plinfo(uint16_t flags, int16_t segno) : d_flags(flags), d_segno(segno){}; + +void plinfo::reset() +{ + d_flags = 0; + d_segno = 0; +} + +void plinfo::from_tag_value(uint32_t tag_value) +{ + auto native_val = boost::endian::big_to_native(tag_value); + d_flags = (native_val >> 16) & 0xFFFF; + d_segno = native_val & 0xFFFF; +} + +uint32_t plinfo::get_tag_value() const +{ + return boost::endian::native_to_big(((d_flags & 0xFFFF) << 16) | (d_segno & 0xFFFF)); +} + +// accessors +bool plinfo::field_sync1_p() const { return (d_flags & fl_field_sync1) != 0; } +bool plinfo::field_sync2_p() const { return (d_flags & fl_field_sync2) != 0; } +bool plinfo::field_sync_p() const { return field_sync1_p() || field_sync2_p(); } + +bool plinfo::regular_seg_p() const { return (d_flags & fl_regular_seg) != 0; } + +bool plinfo::in_field1_p() const { return (d_flags & fl_field2) == 0; } +bool plinfo::in_field2_p() const { return (d_flags & fl_field2) != 0; } + +bool plinfo::first_regular_seg_p() const { return (d_flags & fl_first_regular_seg) != 0; } + +bool plinfo::transport_error_p() const { return (d_flags & fl_transport_error) != 0; } + +unsigned int plinfo::segno() const { return d_segno; } +unsigned int plinfo::flags() const { return d_flags; } + +// setters + +void plinfo::set_field_sync1() +{ + d_segno = 0; + d_flags = fl_field_sync1; +} + +void plinfo::set_field_sync2() +{ + d_segno = 0; + d_flags = fl_field_sync2 | fl_field2; +} + +void plinfo::set_regular_seg(bool field2, int segno) +{ + d_segno = segno; + d_flags = fl_regular_seg; + if (segno == 0) + d_flags |= fl_first_regular_seg; + if (segno >= ATSC_DSEGS_PER_FIELD) + d_flags |= fl_transport_error; + if (field2) + d_flags |= fl_field2; +} + +void plinfo::set_transport_error(bool error) +{ + if (error) + d_flags |= fl_transport_error; + else + d_flags &= ~fl_transport_error; +} + +void plinfo::delay(plinfo& out, const plinfo& in, int nsegs_of_delay) +{ + assert(in.regular_seg_p()); + assert(nsegs_of_delay >= 0); + + int s = in.segno(); + if (in.in_field2_p()) + s += ATSC_DSEGS_PER_FIELD; + + s -= nsegs_of_delay; + if (s < 0) + s += 2 * ATSC_DSEGS_PER_FIELD; + + if (s < ATSC_DSEGS_PER_FIELD) + out.set_regular_seg(false, s); // field 1 + else + out.set_regular_seg(true, s - ATSC_DSEGS_PER_FIELD); // field 2 +} + + +} /* namespace dtv */ +} /* namespace gr */ diff --git a/gr-dtv/lib/atsc/atsc_randomize.cc b/gr-dtv/lib/atsc/atsc_randomize.cc index d148dcd748..a4e0e611b5 100644 --- a/gr-dtv/lib/atsc/atsc_randomize.cc +++ b/gr-dtv/lib/atsc/atsc_randomize.cc @@ -53,13 +53,12 @@ void atsc_randomize::randomize(atsc_mpeg_packet_no_sync& out, const atsc_mpeg_pa out.data[i] = in.data[i + 1] ^ output_and_clk(); } -void atsc_randomize::derandomize(atsc_mpeg_packet& out, - const atsc_mpeg_packet_no_sync& in) +void atsc_randomize::derandomize(uint8_t* out, const uint8_t* in) { - out.data[0] = MPEG_SYNC_BYTE; // add sync byte to beginning of packet + out[0] = MPEG_SYNC_BYTE; // add sync byte to beginning of packet for (int i = 0; i < ATSC_MPEG_DATA_LENGTH; i++) - out.data[i + 1] = in.data[i] ^ output_and_clk(); + out[i + 1] = in[i] ^ output_and_clk(); } diff --git a/gr-dtv/lib/atsc/atsc_randomize.h b/gr-dtv/lib/atsc/atsc_randomize.h index e005b8d40f..9d52fbcf10 100644 --- a/gr-dtv/lib/atsc/atsc_randomize.h +++ b/gr-dtv/lib/atsc/atsc_randomize.h @@ -12,6 +12,7 @@ #define INCLUDED_ATSC_RANDOMIZE_H #include "atsc_types.h" +#include <stdint.h> namespace gr { namespace dtv { @@ -33,7 +34,7 @@ public: void randomize(atsc_mpeg_packet_no_sync& out, const atsc_mpeg_packet& in); //! derandomize (de-whiten) mpeg packet and add leading MPEG-2 sync byte - void derandomize(atsc_mpeg_packet& out, const atsc_mpeg_packet_no_sync& in); + void derandomize(uint8_t* out, const uint8_t* in); unsigned int state() const { return d_state; } diff --git a/gr-dtv/lib/atsc/atsc_rs_decoder_impl.cc b/gr-dtv/lib/atsc/atsc_rs_decoder_impl.cc index a22fffe537..4e6afe2753 100644 --- a/gr-dtv/lib/atsc/atsc_rs_decoder_impl.cc +++ b/gr-dtv/lib/atsc/atsc_rs_decoder_impl.cc @@ -35,35 +35,38 @@ atsc_rs_decoder::sptr atsc_rs_decoder::make() } atsc_rs_decoder_impl::atsc_rs_decoder_impl() - : gr::sync_block("dtv_atsc_rs_decoder", - io_signature::make(1, 1, sizeof(atsc_mpeg_packet_rs_encoded)), - io_signature::make(1, 1, sizeof(atsc_mpeg_packet_no_sync))) + : gr::sync_block( + "dtv_atsc_rs_decoder", + io_signature::make(1, 1, sizeof(uint8_t) * ATSC_MPEG_RS_ENCODED_LENGTH), + io_signature::make(1, 1, sizeof(uint8_t) * ATSC_MPEG_PKT_LENGTH)) { d_rs = init_rs_char( rs_init_symsize, rs_init_gfpoly, rs_init_fcr, rs_init_prim, rs_init_nroots); assert(d_rs != 0); - d_nerrors_corrrected_count = 0; + d_nerrors_corrected_count = 0; d_bad_packet_count = 0; d_total_packets = 0; + + set_tag_propagation_policy(TPP_CUSTOM); } -int atsc_rs_decoder_impl::decode(atsc_mpeg_packet_no_sync& out, - const atsc_mpeg_packet_rs_encoded& in) +int atsc_rs_decoder_impl::decode(uint8_t* out, const uint8_t* in) { unsigned char tmp[N]; int ncorrections; - assert((int)(amount_of_pad + sizeof(in.data)) == N); + // assert((int)(amount_of_pad + sizeof(in.data)) == N); + assert((int)(amount_of_pad + ATSC_MPEG_RS_ENCODED_LENGTH) == N); // add missing prefix zero padding to message memset(tmp, 0, amount_of_pad); - memcpy(&tmp[amount_of_pad], in.data, sizeof(in.data)); + memcpy(&tmp[amount_of_pad], in, ATSC_MPEG_RS_ENCODED_LENGTH); // correct message... ncorrections = decode_rs_char(d_rs, tmp, 0, 0); // copy corrected message to output, skipping prefix zero padding - memcpy(out.data, &tmp[amount_of_pad], sizeof(out.data)); + memcpy(out, &tmp[amount_of_pad], ATSC_MPEG_PKT_LENGTH); return ncorrections; } @@ -77,7 +80,7 @@ atsc_rs_decoder_impl::~atsc_rs_decoder_impl() int atsc_rs_decoder_impl::num_errors_corrected() const { - return d_nerrors_corrrected_count; + return d_nerrors_corrected_count; } int atsc_rs_decoder_impl::num_bad_packets() const { return d_bad_packet_count; } @@ -88,29 +91,44 @@ int atsc_rs_decoder_impl::work(int noutput_items, gr_vector_const_void_star& input_items, gr_vector_void_star& output_items) { - const atsc_mpeg_packet_rs_encoded* in = - (const atsc_mpeg_packet_rs_encoded*)input_items[0]; - atsc_mpeg_packet_no_sync* out = (atsc_mpeg_packet_no_sync*)output_items[0]; + auto in = static_cast<const uint8_t*>(input_items[0]); + auto out = static_cast<uint8_t*>(output_items[0]); + std::vector<tag_t> tags; + auto tag_pmt = pmt::intern("plinfo"); for (int i = 0; i < noutput_items; i++) { - assert(in[i].pli.regular_seg_p()); - out[i].pli = in[i].pli; // copy pipeline info... + plinfo pli_in; + get_tags_in_window(tags, 0, i, i + 1, tag_pmt); + if (tags.size() > 0) { + pli_in.from_tag_value(pmt::to_uint64(tags[0].value)); + } else { + throw std::runtime_error( + "Atsc Viterbi Decoder: Plinfo Tag not found on sample"); + } + + assert(pli_in.regular_seg_p()); - int nerrors_corrrected = decode(out[i], in[i]); - out[i].pli.set_transport_error(nerrors_corrrected == -1); - if (nerrors_corrrected == -1) { + plinfo pli_out = pli_in; // copy pipeline info... + + + int nerrors_corrected = + decode(&out[i * ATSC_MPEG_PKT_LENGTH], &in[i * ATSC_MPEG_RS_ENCODED_LENGTH]); + pli_out.set_transport_error(nerrors_corrected == -1); + if (nerrors_corrected == -1) { d_bad_packet_count++; - d_nerrors_corrrected_count += - 10; // lower bound estimate; most this RS can fix + d_nerrors_corrected_count += 10; // lower bound estimate; most this RS can fix } else { - d_nerrors_corrrected_count += nerrors_corrrected; + d_nerrors_corrected_count += nerrors_corrected; } + add_item_tag( + 0, nitems_written(0) + i, tag_pmt, pmt::from_uint64(pli_out.get_tag_value())); + d_total_packets++; #if 0 if (d_total_packets > 1000) { GR_LOG_INFO(d_logger, boost::format("Error rate: %1%\tPacket error rate: %2%") \ - % ((float)d_nerrors_corrrected_count/(ATSC_MPEG_DATA_LENGTH*d_total_packets)) + % ((float)d_nerrors_corrected_count/(ATSC_MPEG_PKT_LENGTH*d_total_packets)) % ((float)d_bad_packet_count/d_total_packets)); } #endif diff --git a/gr-dtv/lib/atsc/atsc_rs_decoder_impl.h b/gr-dtv/lib/atsc/atsc_rs_decoder_impl.h index 71a01ee436..c7b3c5d1c9 100644 --- a/gr-dtv/lib/atsc/atsc_rs_decoder_impl.h +++ b/gr-dtv/lib/atsc/atsc_rs_decoder_impl.h @@ -24,7 +24,7 @@ namespace dtv { class atsc_rs_decoder_impl : public atsc_rs_decoder { private: - int d_nerrors_corrrected_count; + int d_nerrors_corrected_count; int d_bad_packet_count; int d_total_packets; void* d_rs; @@ -43,7 +43,7 @@ public: * Decode RS encoded packet. * \returns a count of corrected symbols, or -1 if the block was uncorrectible. */ - int decode(atsc_mpeg_packet_no_sync& out, const atsc_mpeg_packet_rs_encoded& in); + int decode(uint8_t* out, const uint8_t* in); int work(int noutput_items, gr_vector_const_void_star& input_items, diff --git a/gr-dtv/lib/atsc/atsc_sync_impl.cc b/gr-dtv/lib/atsc/atsc_sync_impl.cc index 2cff86358c..d21ebe7c39 100644 --- a/gr-dtv/lib/atsc/atsc_sync_impl.cc +++ b/gr-dtv/lib/atsc/atsc_sync_impl.cc @@ -34,7 +34,7 @@ atsc_sync::sptr atsc_sync::make(float rate) atsc_sync_impl::atsc_sync_impl(float rate) : gr::block("dtv_atsc_sync", io_signature::make(1, 1, sizeof(float)), - io_signature::make(1, 1, sizeof(atsc_soft_data_segment))), + io_signature::make(1, 1, ATSC_DATA_SEGMENT_LENGTH * sizeof(float))), d_rx_clock_to_symbol_freq(rate / ATSC_SYMBOL_RATE), d_si(0) { @@ -82,15 +82,15 @@ int atsc_sync_impl::general_work(int noutput_items, gr_vector_const_void_star& input_items, gr_vector_void_star& output_items) { - const float* in = (const float*)input_items[0]; - atsc_soft_data_segment* soft_data_segment_out = - (atsc_soft_data_segment*)output_items[0]; + const float* in = static_cast<const float*>(input_items[0]); + float* out = static_cast<float*>(output_items[0]); float interp_sample; // amount actually consumed d_si = 0; + for (d_output_produced = 0; d_output_produced < noutput_items && (d_si + (int)d_interp.ntaps()) < ninput_items[0];) { // First we interpolate a sample from input to work with @@ -150,8 +150,6 @@ int atsc_sync_impl::general_work(int noutput_items, // d_sample_mem[best_correlation_index - 1] - // d_sample_mem[best_correlation_index]; - // printf( "d_timing_adjust = %f\n", d_timing_adjust ); - int corr_count = best_correlation_index; d_timing_adjust = -d_sample_mem[corr_count--]; @@ -180,8 +178,9 @@ int atsc_sync_impl::general_work(int noutput_items, d_data_mem[d_symbol_index] = interp_sample; if (d_symbol_index >= (ATSC_DATA_SEGMENT_LENGTH - 1)) { - for (int i = 0; i < ATSC_DATA_SEGMENT_LENGTH; i++) - soft_data_segment_out[d_output_produced].data[i] = d_data_mem[i]; + memcpy(&out[d_output_produced * ATSC_DATA_SEGMENT_LENGTH], + d_data_mem, + ATSC_DATA_SEGMENT_LENGTH * sizeof(float)); d_output_produced++; } } diff --git a/gr-dtv/lib/atsc/atsc_trellis_encoder_impl.cc b/gr-dtv/lib/atsc/atsc_trellis_encoder_impl.cc index 3cddcba7ae..59c5a0d223 100644 --- a/gr-dtv/lib/atsc/atsc_trellis_encoder_impl.cc +++ b/gr-dtv/lib/atsc/atsc_trellis_encoder_impl.cc @@ -71,7 +71,6 @@ void atsc_trellis_encoder_impl::encode(atsc_data_segment out[NCODERS], // copy input into contiguous temporary buffer for (int i = 0; i < NCODERS; i++) { assert(in[i].pli.regular_seg_p()); - plinfo::sanity_check(in[i].pli); memcpy(&in_copy[i * INPUT_SIZE / NCODERS], &in[i].data[0], ATSC_MPEG_RS_ENCODED_LENGTH * sizeof(in_copy[0])); @@ -91,7 +90,6 @@ void atsc_trellis_encoder_impl::encode(atsc_data_segment out[NCODERS], // copy pipeline info out[i].pli = in[i].pli; - plinfo::sanity_check(out[i].pli); assert(out[i].pli.regular_seg_p()); } } diff --git a/gr-dtv/lib/atsc/atsc_types.h b/gr-dtv/lib/atsc/atsc_types.h index 6d48c91174..59ea3bbf59 100644 --- a/gr-dtv/lib/atsc/atsc_types.h +++ b/gr-dtv/lib/atsc/atsc_types.h @@ -15,151 +15,11 @@ #include <cassert> #include <cstring> +#include <gnuradio/dtv/atsc_plinfo.h> + namespace gr { namespace dtv { -/*! - * \brief pipeline info that flows with data - * - * Not all modules need all the info - */ -class plinfo -{ -public: - plinfo() : _flags(0), _segno(0) {} - - // accessors - - bool field_sync1_p() const { return (_flags & fl_field_sync1) != 0; } - bool field_sync2_p() const { return (_flags & fl_field_sync2) != 0; } - bool field_sync_p() const { return field_sync1_p() || field_sync2_p(); } - - bool regular_seg_p() const { return (_flags & fl_regular_seg) != 0; } - - bool in_field1_p() const { return (_flags & fl_field2) == 0; } - bool in_field2_p() const { return (_flags & fl_field2) != 0; } - - bool first_regular_seg_p() const { return (_flags & fl_first_regular_seg) != 0; } - - bool transport_error_p() const { return (_flags & fl_transport_error) != 0; } - - unsigned int segno() const { return _segno; } - unsigned int flags() const { return _flags; } - - // setters - - void set_field_sync1() - { - _segno = 0; - _flags = fl_field_sync1; - } - - void set_field_sync2() - { - _segno = 0; - _flags = fl_field_sync2 | fl_field2; - } - - void set_regular_seg(bool field2, int segno) - { - // assert (0 <= segno && segno < ATSC_DSEGS_PER_FIELD); - _segno = segno; - _flags = fl_regular_seg; - if (segno == 0) - _flags |= fl_first_regular_seg; - if (segno >= ATSC_DSEGS_PER_FIELD) - _flags |= fl_transport_error; - if (field2) - _flags |= fl_field2; - } - - void set_transport_error(bool error) - { - if (error) - _flags |= fl_transport_error; - else - _flags &= ~fl_transport_error; - } - - // overload equality operator - bool operator==(const plinfo& other) const - { - return (_flags == other._flags && _segno == other._segno); - } - - bool operator!=(const plinfo& other) const - { - return !(_flags == other._flags && _segno == other._segno); - } - - /*! - * Set \p OUT such that it reflects a \p NSEGS_OF_DELAY - * pipeline delay from \p IN. - */ - static void delay(plinfo& out, const plinfo& in, int nsegs_of_delay) - { - assert(in.regular_seg_p()); - assert(nsegs_of_delay >= 0); - - int s = in.segno(); - if (in.in_field2_p()) - s += ATSC_DSEGS_PER_FIELD; - - s -= nsegs_of_delay; - if (s < 0) - s += 2 * ATSC_DSEGS_PER_FIELD; - - // assert (0 <= s && s < 2 * ATSC_DSEGS_PER_FIELD); - - if (s < ATSC_DSEGS_PER_FIELD) - out.set_regular_seg(false, s); // field 1 - else - out.set_regular_seg(true, s - ATSC_DSEGS_PER_FIELD); // field 2 - } - - /*! - * confirm that \p X is plausible - */ - static void sanity_check(const plinfo& in) - { - // basic sanity checks... - // assert (x.segno () >= 0); - // assert (x.segno () < (unsigned) ATSC_DSEGS_PER_FIELD); - // assert ((x.flags () & ~0x3f) == 0); - - // assert (x.regular_seg_p () ^ x.field_sync_p ()); - // assert ((x.segno () != 0) ^ x.first_regular_seg_p ()); - } - - unsigned short _flags; // bitmask - short _segno; // segment number [-1,311] -1 is the field sync segment - -protected: - // these three are mutually exclusive - // This is a regular data segment. - static constexpr int fl_regular_seg = 0x0001; - // This is a field sync segment, for 1st half of a field. - static constexpr int fl_field_sync1 = 0x0002; - // This is a field sync segment, for 2nd half of a field. - static constexpr int fl_field_sync2 = 0x0004; - - // This bit is on ONLY when fl_regular_seg is set AND when this is - // the first regular data segment AFTER a field sync segment. This - // segment causes various processing modules to reset. - static constexpr int fl_first_regular_seg = 0x0008; - - // which field are we in? - static constexpr int fl_field2 = 0x0010; // else field 1 - - // This bit is set when Reed-Solomon decoding detects an error that it - // can't correct. Note that other error detection (e.g. Viterbi) do not - // set it, since Reed-Solomon will correct many of those. This bit is - // then copied into the final Transport Stream packet so that MPEG - // software can see that the 188-byte data segment has been corrupted. - static constexpr int fl_transport_error = 0x0020; -}; - - class atsc_mpeg_packet { public: @@ -255,17 +115,6 @@ public: plinfo pli; float data[ATSC_DATA_SEGMENT_LENGTH]; unsigned char _pad_[NPAD]; // pad to power of 2 (4096) - - // overload equality operator - bool operator==(const atsc_data_segment& other) const - { - return std::memcmp(data, other.data, sizeof(data)) == 0; - } - - bool operator!=(const atsc_data_segment& other) const - { - return !(std::memcmp(data, other.data, sizeof(data)) == 0); - } }; } /* namespace dtv */ diff --git a/gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.cc b/gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.cc index e02649861e..1e53c78aba 100644 --- a/gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.cc +++ b/gr-dtv/lib/atsc/atsc_viterbi_decoder_impl.cc @@ -26,9 +26,10 @@ atsc_viterbi_decoder::sptr atsc_viterbi_decoder::make() } 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))) + : sync_block( + "dtv_atsc_viterbi_decoder", + io_signature::make(1, 1, sizeof(float) * ATSC_DATA_SEGMENT_LENGTH), + io_signature::make(1, 1, sizeof(unsigned char) * ATSC_MPEG_RS_ENCODED_LENGTH)) { set_output_multiple(NCODERS); @@ -49,6 +50,8 @@ atsc_viterbi_decoder_impl::atsc_viterbi_decoder_impl() fifo.emplace_back(fifo_size); reset(); + + set_tag_propagation_policy(TPP_CUSTOM); } atsc_viterbi_decoder_impl::~atsc_viterbi_decoder_impl() {} @@ -71,8 +74,8 @@ 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]; + auto in = static_cast<const float*>(input_items[0]); + auto out = static_cast<unsigned char*>(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 @@ -87,12 +90,17 @@ int atsc_viterbi_decoder_impl::work(int noutput_items, unsigned char out_copy[OUTPUT_SIZE]; + std::vector<tag_t> tags; + auto tag_pmt = pmt::intern("plinfo"); 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]; + symbols[encoder][k] = in[(i + (enco_which_syms[encoder][k] / 832)) * + ATSC_DATA_SEGMENT_LENGTH + + enco_which_syms[encoder][k] % 832]; + /* Now run each of the 12 Viterbi decoders over their subset of the input symbols */ @@ -114,12 +122,26 @@ int atsc_viterbi_decoder_impl::work(int noutput_items, // copy output from contiguous temp buffer into final output for (int j = 0; j < NCODERS; j++) { - memcpy(&out[i + j].data[0], + plinfo pli_in; + get_tags_in_window(tags, 0, i + j, i + j + 1, tag_pmt); + if (tags.size() > 0) { + pli_in.from_tag_value(pmt::to_uint64(tags[0].value)); + } else { + throw std::runtime_error("No plinfo on tag"); + } + + memcpy(&out[(i * NCODERS + j) * ATSC_MPEG_RS_ENCODED_LENGTH], &out_copy[j * OUTPUT_SIZE / NCODERS], ATSC_MPEG_RS_ENCODED_LENGTH * sizeof(out_copy[0])); + plinfo pli_out; // adjust pipeline info to reflect 12 segment delay - plinfo::delay(out[i + j].pli, in[i + j].pli, NCODERS); + plinfo::delay(pli_out, pli_in, NCODERS); + + add_item_tag(0, + nitems_written(0) + i + j, + tag_pmt, + pmt::from_uint64(pli_out.get_tag_value())); } } |