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