1 /* -*- c++ -*- */
2 /*
3 * Copyright 2015,2018,2019 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 "burst_shaper_impl.h"
28 #include <gnuradio/io_signature.h>
29 #include <volk/volk.h>
30 #include <boost/format.hpp>
31 #include <algorithm>
32
33 namespace gr {
34 namespace digital {
35
36 template <class T>
make(const std::vector<T> & taps,int pre_padding,int post_padding,bool insert_phasing,const std::string & length_tag_name)37 typename burst_shaper<T>::sptr burst_shaper<T>::make(const std::vector<T>& taps,
38 int pre_padding,
39 int post_padding,
40 bool insert_phasing,
41 const std::string& length_tag_name)
42 {
43 return gnuradio::get_initial_sptr(new burst_shaper_impl<T>(
44 taps, pre_padding, post_padding, insert_phasing, length_tag_name));
45 }
46
47 template <class T>
burst_shaper_impl(const std::vector<T> & taps,int pre_padding,int post_padding,bool insert_phasing,const std::string & length_tag_name)48 burst_shaper_impl<T>::burst_shaper_impl(const std::vector<T>& taps,
49 int pre_padding,
50 int post_padding,
51 bool insert_phasing,
52 const std::string& length_tag_name)
53 : gr::block("burst_shaper",
54 gr::io_signature::make(1, 1, sizeof(T)),
55 gr::io_signature::make(1, 1, sizeof(T))),
56 d_up_ramp(taps.begin(), taps.begin() + taps.size() / 2 + taps.size() % 2),
57 d_down_ramp(taps.begin() + taps.size() / 2, taps.end()),
58 d_nprepad(pre_padding),
59 d_npostpad(post_padding),
60 d_insert_phasing(insert_phasing),
61 d_length_tag_key(pmt::string_to_symbol(length_tag_name)),
62 d_ncopy(0),
63 d_limit(0),
64 d_index(0),
65 d_length_tag_offset(0),
66 d_finished(false),
67 d_state(STATE_WAIT)
68 {
69 assert(d_up_ramp.size() == d_down_ramp.size());
70
71 d_up_phasing.resize(d_up_ramp.size());
72 d_down_phasing.resize(d_down_ramp.size());
73
74 T symbol;
75 for (unsigned int i = 0; i < d_up_ramp.size(); i++) {
76 symbol = (i % 2 == 0) ? T(1.0f) : T(-1.0f);
77 d_up_phasing[i] = symbol * d_up_ramp[i];
78 d_down_phasing[i] = symbol * d_down_ramp[i];
79 }
80
81 // this->set_relative_rate(1, 1);
82 this->set_tag_propagation_policy(gr::block::TPP_DONT);
83 }
84
85 template <class T>
~burst_shaper_impl()86 burst_shaper_impl<T>::~burst_shaper_impl()
87 {
88 }
89
90 template <class T>
forecast(int noutput_items,gr_vector_int & ninput_items_required)91 void burst_shaper_impl<T>::forecast(int noutput_items,
92 gr_vector_int& ninput_items_required)
93 {
94 switch (d_state) {
95 case (STATE_RAMPDOWN):
96 // If inserting phasing; we don't need any input
97 if (d_insert_phasing) {
98 ninput_items_required[0] = 0;
99 } else {
100 ninput_items_required[0] = noutput_items;
101 }
102 break;
103 case (STATE_POSTPAD):
104 // Padding 0's requires no input
105 ninput_items_required[0] = 0;
106 break;
107 default:
108 ninput_items_required[0] = noutput_items;
109 }
110 }
111
112 template <class T>
general_work(int noutput_items,gr_vector_int & ninput_items,gr_vector_const_void_star & input_items,gr_vector_void_star & output_items)113 int burst_shaper_impl<T>::general_work(int noutput_items,
114 gr_vector_int& ninput_items,
115 gr_vector_const_void_star& input_items,
116 gr_vector_void_star& output_items)
117 {
118 const T* in = reinterpret_cast<const T*>(input_items[0]);
119 T* out = reinterpret_cast<T*>(output_items[0]);
120
121 int nwritten = 0;
122 int nread = 0;
123 int nspace = 0;
124 int nskip = 0;
125 int curr_tag_index = 0;
126
127 std::vector<tag_t> length_tags;
128 this->get_tags_in_window(length_tags, 0, 0, ninput_items[0], d_length_tag_key);
129 std::sort(length_tags.rbegin(), length_tags.rend(), tag_t::offset_compare);
130
131 while (nwritten < noutput_items) {
132 // Only check the nread condition if we are actually reading
133 // from the input stream.
134 if (((d_state != STATE_RAMPDOWN) && (d_state != STATE_POSTPAD)) ||
135 ((d_state == STATE_RAMPDOWN) && !d_insert_phasing)) {
136 if (nread >= ninput_items[0]) {
137 break;
138 }
139 }
140
141 if (d_finished) {
142 d_finished = false;
143 break;
144 }
145 nspace = noutput_items - nwritten;
146 switch (d_state) {
147 case (STATE_WAIT):
148 if (!length_tags.empty()) {
149 d_length_tag_offset = length_tags.back().offset;
150 curr_tag_index = (int)(d_length_tag_offset - this->nitems_read(0));
151 d_ncopy = pmt::to_long(length_tags.back().value);
152 length_tags.pop_back();
153 nskip = curr_tag_index - nread;
154 add_length_tag(nwritten);
155 propagate_tags(curr_tag_index, nwritten, 1, false);
156 enter_prepad();
157 } else {
158 nskip = ninput_items[0] - nread;
159 }
160 if (nskip > 0) {
161 GR_LOG_WARN(this->d_logger,
162 boost::format("Dropping %1% samples") % nskip);
163 nread += nskip;
164 in += nskip;
165 }
166 break;
167
168 case (STATE_PREPAD):
169 write_padding(out, nwritten, nspace);
170 if (d_index == d_limit)
171 enter_rampup();
172 break;
173
174 case (STATE_RAMPUP):
175 apply_ramp(out, in, nwritten, nread, nspace);
176 if (d_index == d_limit)
177 enter_copy();
178 break;
179
180 case (STATE_COPY):
181 copy_items(out, in, nwritten, nread, nspace);
182 if (d_index == d_limit)
183 enter_rampdown();
184 break;
185
186 case (STATE_RAMPDOWN):
187 apply_ramp(out, in, nwritten, nread, nspace);
188 if (d_index == d_limit)
189 enter_postpad();
190 break;
191
192 case (STATE_POSTPAD):
193 write_padding(out, nwritten, nspace);
194 if (d_index == d_limit)
195 enter_wait();
196 break;
197
198 default:
199 throw std::runtime_error("burst_shaper: invalid state");
200 }
201 }
202
203 this->consume_each(nread);
204
205 return nwritten;
206 }
207
208 template <class T>
prefix_length() const209 int burst_shaper_impl<T>::prefix_length() const
210 {
211 return (d_insert_phasing) ? d_nprepad + d_up_ramp.size() : d_nprepad;
212 }
213
214 template <class T>
suffix_length() const215 int burst_shaper_impl<T>::suffix_length() const
216 {
217 return (d_insert_phasing) ? d_npostpad + d_down_ramp.size() : d_npostpad;
218 }
219
220 template <class T>
write_padding(T * & dst,int & nwritten,int nspace)221 void burst_shaper_impl<T>::write_padding(T*& dst, int& nwritten, int nspace)
222 {
223 int nprocess = std::min(d_limit - d_index, nspace);
224 std::fill_n(dst, nprocess, 0x00);
225 dst += nprocess;
226 nwritten += nprocess;
227 d_index += nprocess;
228 }
229
230 template <class T>
copy_items(T * & dst,const T * & src,int & nwritten,int & nread,int nspace)231 void burst_shaper_impl<T>::copy_items(
232 T*& dst, const T*& src, int& nwritten, int& nread, int nspace)
233 {
234 int nprocess = std::min(d_limit - d_index, nspace);
235 propagate_tags(nread, nwritten, nprocess);
236 std::memcpy(dst, src, nprocess * sizeof(T));
237 dst += nprocess;
238 nwritten += nprocess;
239 src += nprocess;
240 nread += nprocess;
241 d_index += nprocess;
242 }
243
244 template <>
apply_ramp(gr_complex * & dst,const gr_complex * & src,int & nwritten,int & nread,int nspace)245 void burst_shaper_impl<gr_complex>::apply_ramp(
246 gr_complex*& dst, const gr_complex*& src, int& nwritten, int& nread, int nspace)
247 {
248 int nprocess = std::min(d_limit - d_index, nspace);
249 gr_complex* phasing;
250 const gr_complex* ramp;
251
252 if (d_state == STATE_RAMPUP) {
253 phasing = &d_up_phasing[d_index];
254 ramp = &d_up_ramp[d_index];
255 } else {
256 phasing = &d_down_phasing[d_index];
257 ramp = &d_down_ramp[d_index];
258 }
259
260 if (d_insert_phasing)
261 std::memcpy(dst, phasing, nprocess * sizeof(gr_complex));
262 else {
263 propagate_tags(nread, nwritten, nprocess);
264 volk_32fc_x2_multiply_32fc(dst, src, ramp, nprocess);
265 src += nprocess;
266 nread += nprocess;
267 }
268
269 dst += nprocess;
270 nwritten += nprocess;
271 d_index += nprocess;
272 }
273
274 template <>
apply_ramp(float * & dst,const float * & src,int & nwritten,int & nread,int nspace)275 void burst_shaper_impl<float>::apply_ramp(
276 float*& dst, const float*& src, int& nwritten, int& nread, int nspace)
277 {
278 int nprocess = std::min(d_limit - d_index, nspace);
279 float* phasing;
280 const float* ramp;
281
282 if (d_state == STATE_RAMPUP) {
283 phasing = &d_up_phasing[d_index];
284 ramp = &d_up_ramp[d_index];
285 } else {
286 phasing = &d_down_phasing[d_index];
287 ramp = &d_down_ramp[d_index];
288 }
289
290 if (d_insert_phasing)
291 std::memcpy(dst, phasing, nprocess * sizeof(float));
292 else {
293 propagate_tags(nread, nwritten, nprocess);
294 volk_32f_x2_multiply_32f(dst, src, ramp, nprocess);
295 src += nprocess;
296 nread += nprocess;
297 }
298
299 dst += nprocess;
300 nwritten += nprocess;
301 d_index += nprocess;
302 }
303
304
305 template <class T>
add_length_tag(int offset)306 void burst_shaper_impl<T>::add_length_tag(int offset)
307 {
308 this->add_item_tag(0,
309 this->nitems_written(0) + offset,
310 d_length_tag_key,
311 pmt::from_long(d_ncopy + prefix_length() + suffix_length()),
312 pmt::string_to_symbol(this->name()));
313 }
314
315 template <class T>
propagate_tags(int in_offset,int out_offset,int count,bool skip)316 void burst_shaper_impl<T>::propagate_tags(int in_offset,
317 int out_offset,
318 int count,
319 bool skip)
320 {
321 uint64_t abs_start = this->nitems_read(0) + in_offset;
322 uint64_t abs_end = abs_start + count;
323 uint64_t abs_offset = this->nitems_written(0) + out_offset;
324 tag_t temp_tag;
325
326 std::vector<tag_t> tags;
327 std::vector<tag_t>::iterator it;
328
329 this->get_tags_in_range(tags, 0, abs_start, abs_end);
330
331 for (it = tags.begin(); it != tags.end(); it++) {
332 if (!pmt::equal(it->key, d_length_tag_key)) {
333 if (skip && (it->offset == d_length_tag_offset))
334 continue;
335 temp_tag = *it;
336 temp_tag.offset = abs_offset + it->offset - abs_start;
337 this->add_item_tag(0, temp_tag);
338 }
339 }
340 }
341
342 template <class T>
enter_wait()343 void burst_shaper_impl<T>::enter_wait()
344 {
345 d_finished = true;
346 d_index = 0;
347 d_state = STATE_WAIT;
348 }
349
350 template <class T>
enter_prepad()351 void burst_shaper_impl<T>::enter_prepad()
352 {
353 d_limit = d_nprepad;
354 d_index = 0;
355 d_state = STATE_PREPAD;
356 }
357
358 template <class T>
enter_rampup()359 void burst_shaper_impl<T>::enter_rampup()
360 {
361 if (d_insert_phasing)
362 d_limit = d_up_ramp.size();
363 else
364 d_limit = std::min((size_t)(d_ncopy / 2), d_up_ramp.size());
365 d_index = 0;
366 d_state = STATE_RAMPUP;
367 }
368
369 template <class T>
enter_copy()370 void burst_shaper_impl<T>::enter_copy()
371 {
372 if (d_insert_phasing)
373 d_limit = d_ncopy;
374 else
375 d_limit = d_ncopy - std::min((size_t)((d_ncopy / 2) * 2),
376 d_up_ramp.size() + d_down_ramp.size());
377 d_index = 0;
378 d_state = STATE_COPY;
379 }
380
381 template <class T>
enter_rampdown()382 void burst_shaper_impl<T>::enter_rampdown()
383 {
384 if (d_insert_phasing)
385 d_limit = d_down_ramp.size();
386 else
387 d_limit = std::min((size_t)(d_ncopy / 2), d_down_ramp.size());
388 d_index = 0;
389 d_state = STATE_RAMPDOWN;
390 }
391
392 template <class T>
enter_postpad()393 void burst_shaper_impl<T>::enter_postpad()
394 {
395 d_limit = d_npostpad;
396 d_index = 0;
397 d_state = STATE_POSTPAD;
398 }
399
400 template class burst_shaper<gr_complex>;
401 template class burst_shaper<float>;
402 } /* namespace digital */
403 } /* namespace gr */
404