1 /* -*- c++ -*- */
2 /*
3 * Copyright 2014 Free Software Foundation, Inc.
4 *
5 * This file is part of GNU Radio
6 *
7 * GNU Radio is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3, or (at your option)
10 * any later version.
11 *
12 * GNU Radio is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Radio; see the file COPYING. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include "atsc_types.h"
28 #include "atsc_viterbi_decoder_impl.h"
29 #include "atsc_viterbi_mux.h"
30 #include <gnuradio/io_signature.h>
31
32 namespace gr {
33 namespace dtv {
34
make()35 atsc_viterbi_decoder::sptr atsc_viterbi_decoder::make()
36 {
37 return gnuradio::get_initial_sptr(new atsc_viterbi_decoder_impl());
38 }
39
atsc_viterbi_decoder_impl()40 atsc_viterbi_decoder_impl::atsc_viterbi_decoder_impl()
41 : sync_block("dtv_atsc_viterbi_decoder",
42 io_signature::make(1, 1, sizeof(atsc_soft_data_segment)),
43 io_signature::make(1, 1, sizeof(atsc_mpeg_packet_rs_encoded)))
44 {
45 set_output_multiple(NCODERS);
46
47 /*
48 * These fifo's handle the alignment problem caused by the
49 * inherent decoding delay of the individual viterbi decoders.
50 * The net result is that this entire block has a pipeline latency
51 * of 12 complete segments.
52 *
53 * If anybody cares, it is possible to do it with less delay, but
54 * this approach is at least somewhat understandable...
55 */
56
57 // the -4 is for the 4 sync symbols
58 int fifo_size = ATSC_DATA_SEGMENT_LENGTH - 4 - viterbi[0].delay();
59 for (int i = 0; i < NCODERS; i++)
60 fifo[i] = new fifo_t(fifo_size);
61
62 reset();
63 }
64
~atsc_viterbi_decoder_impl()65 atsc_viterbi_decoder_impl::~atsc_viterbi_decoder_impl()
66 {
67 for (int i = 0; i < NCODERS; i++)
68 delete fifo[i];
69 }
70
reset()71 void atsc_viterbi_decoder_impl::reset()
72 {
73 for (int i = 0; i < NCODERS; i++)
74 fifo[i]->reset();
75 }
76
decoder_metrics() const77 std::vector<float> atsc_viterbi_decoder_impl::decoder_metrics() const
78 {
79 std::vector<float> metrics(NCODERS);
80 for (int i = 0; i < NCODERS; i++)
81 metrics[i] = viterbi[i].best_state_metric();
82 return metrics;
83 }
84
work(int noutput_items,gr_vector_const_void_star & input_items,gr_vector_void_star & output_items)85 int atsc_viterbi_decoder_impl::work(int noutput_items,
86 gr_vector_const_void_star& input_items,
87 gr_vector_void_star& output_items)
88 {
89 const atsc_soft_data_segment* in = (const atsc_soft_data_segment*)input_items[0];
90 atsc_mpeg_packet_rs_encoded* out = (atsc_mpeg_packet_rs_encoded*)output_items[0];
91
92 // The way the fs_checker works ensures we start getting packets
93 // starting with a field sync, and out input multiple is set to
94 // 12, so we should always get a mod 12 numbered first packet
95 assert(noutput_items % NCODERS == 0);
96
97 int dbwhere;
98 int dbindex;
99 int shift;
100 float symbols[NCODERS][enco_which_max];
101 unsigned char dibits[NCODERS][enco_which_max];
102
103 unsigned char out_copy[OUTPUT_SIZE];
104
105 for (int i = 0; i < noutput_items; i += NCODERS) {
106 /* Build a continuous symbol buffer for each encoder */
107 for (unsigned int encoder = 0; encoder < NCODERS; encoder++)
108 for (unsigned int k = 0; k < enco_which_max; k++)
109 symbols[encoder][k] = in[i + (enco_which_syms[encoder][k] / 832)]
110 .data[enco_which_syms[encoder][k] % 832];
111
112 /* Now run each of the 12 Viterbi decoders over their subset of
113 the input symbols */
114 for (unsigned int encoder = 0; encoder < NCODERS; encoder++)
115 for (unsigned int k = 0; k < enco_which_max; k++)
116 dibits[encoder][k] = viterbi[encoder].decode(symbols[encoder][k]);
117
118 /* Move dibits into their location in the output buffer */
119 for (unsigned int encoder = 0; encoder < NCODERS; encoder++) {
120 for (unsigned int k = 0; k < enco_which_max; k++) {
121 /* Store the dibit into the output data segment */
122 dbwhere = enco_which_dibits[encoder][k];
123 dbindex = dbwhere >> 3;
124 shift = dbwhere & 0x7;
125 out_copy[dbindex] = (out_copy[dbindex] & ~(0x03 << shift)) |
126 (fifo[encoder]->stuff(dibits[encoder][k]) << shift);
127 } /* Symbols fed into one encoder */
128 } /* Encoders */
129
130 // copy output from contiguous temp buffer into final output
131 for (int j = 0; j < NCODERS; j++) {
132 memcpy(&out[i + j].data[0],
133 &out_copy[j * OUTPUT_SIZE / NCODERS],
134 ATSC_MPEG_RS_ENCODED_LENGTH * sizeof(out_copy[0]));
135
136 // adjust pipeline info to reflect 12 segment delay
137 plinfo::delay(out[i + j].pli, in[i + j].pli, NCODERS);
138 }
139 }
140
141 return noutput_items;
142 }
143
setup_rpc()144 void atsc_viterbi_decoder_impl::setup_rpc()
145 {
146 #ifdef GR_CTRLPORT
147 add_rpc_variable(
148 rpcbasic_sptr(new rpcbasic_register_get<atsc_viterbi_decoder, std::vector<float>>(
149 alias(),
150 "decoder_metrics",
151 &atsc_viterbi_decoder::decoder_metrics,
152 pmt::make_f32vector(1, 0),
153 pmt::make_f32vector(1, 100000),
154 pmt::make_f32vector(1, 0),
155 "",
156 "Viterbi decoder metrics",
157 RPC_PRIVLVL_MIN,
158 DISPTIME)));
159 #endif /* GR_CTRLPORT */
160 }
161
162 } /* namespace dtv */
163 } /* namespace gr */
164