1 /* -*- c++ -*- */
2 /*
3 * Copyright 2015,2016 Free Software Foundation, Inc.
4 *
5 * This is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3, or (at your option)
8 * any later version.
9 *
10 * This software is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this software; see the file COPYING. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "dvbt_symbol_inner_interleaver_impl.h"
26 #include <gnuradio/io_signature.h>
27
28 namespace gr {
29 namespace dtv {
30
31 const char dvbt_symbol_inner_interleaver_impl::d_bit_perm_2k[] = { 4, 3, 9, 6, 2,
32 8, 1, 5, 7, 0 };
33 const char dvbt_symbol_inner_interleaver_impl::d_bit_perm_8k[] = { 7, 1, 4, 2, 9, 6,
34 8, 10, 0, 3, 11, 5 };
35
generate_H()36 void dvbt_symbol_inner_interleaver_impl::generate_H()
37 {
38 const int Mmax = d_fft_length;
39 const int Nmax = d_payload_length;
40 const int Nr = int(ceil(log2(d_fft_length)));
41 int q = 0;
42
43 for (int i = 0; i < Mmax; i++) {
44 d_h[q] = ((i % 2) << (Nr - 1)) + calculate_R(i);
45 if (d_h[q] < Nmax) {
46 q++;
47 }
48 }
49 }
50
H(int q)51 int dvbt_symbol_inner_interleaver_impl::H(int q) { return d_h[q]; }
52
calculate_R(int i)53 int dvbt_symbol_inner_interleaver_impl::calculate_R(int i)
54 {
55 const int Nr = int(ceil(log2(d_fft_length)));
56 int reg = 0;
57
58 if (i == 0) {
59 reg = 0;
60 } else if (i == 1) {
61 reg = 0;
62 } else {
63 reg = 1;
64 for (int k = 3; k <= i; k++) {
65 char new_bit = 0;
66
67 if (d_transmission_mode == T2k) {
68 new_bit = (reg ^ (reg >> 3)) & 1;
69 } else if (d_transmission_mode == T8k) {
70 new_bit = (reg ^ (reg >> 1) ^ (reg >> 4) ^ (reg >> 6)) & 1;
71 } else {
72 new_bit = (reg ^ (reg >> 3)) & 1;
73 }
74
75 int mask = (1 << Nr) - 1;
76 reg = ((reg >> 1) | (new_bit << (Nr - 2))) & mask;
77 }
78 }
79
80 int newreg = 0;
81
82 for (int k = 0; k < (Nr - 1); k++) {
83 char bit = (reg >> k) & 1;
84 newreg = newreg | (bit << d_bit_perm[k]);
85 }
86
87 return newreg;
88 }
89
make(int nsize,dvbt_transmission_mode_t transmission,int direction)90 dvbt_symbol_inner_interleaver::sptr dvbt_symbol_inner_interleaver::make(
91 int nsize, dvbt_transmission_mode_t transmission, int direction)
92 {
93 return gnuradio::get_initial_sptr(
94 new dvbt_symbol_inner_interleaver_impl(nsize, transmission, direction));
95 }
96
97 /*
98 * The private constructor
99 */
dvbt_symbol_inner_interleaver_impl(int nsize,dvbt_transmission_mode_t transmission,int direction)100 dvbt_symbol_inner_interleaver_impl::dvbt_symbol_inner_interleaver_impl(
101 int nsize, dvbt_transmission_mode_t transmission, int direction)
102 : block("dvbt_symbol_inner_interleaver",
103 io_signature::make(1, 1, sizeof(unsigned char) * nsize),
104 io_signature::make(1, 1, sizeof(unsigned char) * nsize)),
105 config(gr::dtv::MOD_16QAM,
106 gr::dtv::NH,
107 gr::dtv::C1_2,
108 gr::dtv::C1_2,
109 gr::dtv::GI_1_32,
110 transmission),
111 d_nsize(nsize),
112 d_direction(direction),
113 d_fft_length(0),
114 d_payload_length(0),
115 d_symbol_index(0)
116 {
117 d_symbols_per_frame = config.d_symbols_per_frame;
118 d_transmission_mode = config.d_transmission_mode;
119 d_fft_length = config.d_fft_length;
120 d_payload_length = config.d_payload_length;
121 d_direction = direction;
122
123 // Verify if transmission mode matches with size of block
124 assert(d_payload_length == d_nsize);
125
126 // Allocate memory for h vector
127 d_h = new (std::nothrow) int[d_fft_length];
128 if (d_h == NULL) {
129 GR_LOG_FATAL(d_logger,
130 "Symbol Inner Interleaver, cannot allocate memory for d_h.");
131 throw std::bad_alloc();
132 }
133
134 // Setup bit permutation vectors
135 if (d_transmission_mode == T2k) {
136 d_bit_perm = d_bit_perm_2k;
137 } else if (d_transmission_mode == T8k) {
138 d_bit_perm = d_bit_perm_8k;
139 } else {
140 d_bit_perm = d_bit_perm_2k;
141 }
142
143 // Generate the h function
144 generate_H();
145 }
146
147 /*
148 * Our virtual destructor.
149 */
~dvbt_symbol_inner_interleaver_impl()150 dvbt_symbol_inner_interleaver_impl::~dvbt_symbol_inner_interleaver_impl()
151 {
152 delete[] d_h;
153 }
154
forecast(int noutput_items,gr_vector_int & ninput_items_required)155 void dvbt_symbol_inner_interleaver_impl::forecast(int noutput_items,
156 gr_vector_int& ninput_items_required)
157 {
158 ninput_items_required[0] = noutput_items;
159 }
160
general_work(int noutput_items,gr_vector_int & ninput_items,gr_vector_const_void_star & input_items,gr_vector_void_star & output_items)161 int dvbt_symbol_inner_interleaver_impl::general_work(
162 int noutput_items,
163 gr_vector_int& ninput_items,
164 gr_vector_const_void_star& input_items,
165 gr_vector_void_star& output_items)
166 {
167 const unsigned char* in = (unsigned char*)input_items[0];
168 unsigned char* out = (unsigned char*)output_items[0];
169
170 // Demod reference signals sends a tag per OFDM frame
171 // containing the symbol index.
172 std::vector<tag_t> tags;
173 const uint64_t nread = this->nitems_read(0); // number of items read on port 0
174
175 // Read all tags on the input buffer
176 this->get_tags_in_range(
177 tags, 0, nread, nread + noutput_items, pmt::string_to_symbol("symbol_index"));
178
179 for (int k = 0; k < noutput_items; k++) {
180 int blocks = k * d_nsize;
181
182 if (d_direction) {
183 // Interleave
184 for (int q = 0; q < d_nsize; q++) {
185 if (d_symbol_index % 2) {
186 out[blocks + q] = in[blocks + H(q)];
187 } else {
188 out[blocks + H(q)] = in[blocks + q];
189 }
190 }
191
192 ++d_symbol_index;
193 d_symbol_index = d_symbol_index % d_symbols_per_frame;
194 } else {
195 // Deinterleave
196 d_symbol_index = pmt::to_long(tags[k].value);
197
198 for (int q = 0; q < d_nsize; q++) {
199 if (d_symbol_index % 2) {
200 out[blocks + H(q)] = in[blocks + q];
201 } else {
202 out[blocks + q] = in[blocks + H(q)];
203 }
204 }
205 }
206 }
207
208 // Tell runtime system how many input items we consumed on
209 // each input stream.
210 consume_each(noutput_items);
211
212 // Tell runtime system how many output items we produced.
213 return noutput_items;
214 }
215
216 } /* namespace dtv */
217 } /* namespace gr */
218