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