1 /* -*- c++ -*- */
2 /*
3  * Copyright 2012 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 "keep_one_in_n_impl.h"
28 #include <gnuradio/io_signature.h>
29 
30 namespace gr {
31 namespace blocks {
32 
make(size_t itemsize,int n)33 keep_one_in_n::sptr keep_one_in_n::make(size_t itemsize, int n)
34 {
35     return gnuradio::get_initial_sptr(new keep_one_in_n_impl(itemsize, n));
36 }
37 
keep_one_in_n_impl(size_t itemsize,int n)38 keep_one_in_n_impl::keep_one_in_n_impl(size_t itemsize, int n)
39     : block("keep_one_in_n",
40             io_signature::make(1, 1, itemsize),
41             io_signature::make(1, 1, itemsize)),
42       d_count(n)
43 {
44     // To avoid bad behavior with using set_relative_rate in this block with
45     // VERY large values of n, we will keep track of things ourselves. Using
46     // this to turn off automatic tag propagation, which will be handled
47     // locally in general_work().
48     set_tag_propagation_policy(TPP_DONT);
49 
50     set_n(n);
51 }
52 
set_n(int n)53 void keep_one_in_n_impl::set_n(int n)
54 {
55     if (n < 1) {
56         throw std::invalid_argument("N must be at least 1.");
57     }
58 
59     d_n = n;
60     d_count = n;
61 
62     // keep our internal understanding of the relative rate of this block
63     // don't set the relative rate, though, and we will handle our own
64     // tag propagation.
65     d_decim_rate = 1.0 / (float)d_n;
66 }
67 
general_work(int noutput_items,gr_vector_int & ninput_items,gr_vector_const_void_star & input_items,gr_vector_void_star & output_items)68 int keep_one_in_n_impl::general_work(int noutput_items,
69                                      gr_vector_int& ninput_items,
70                                      gr_vector_const_void_star& input_items,
71                                      gr_vector_void_star& output_items)
72 {
73     const char* in = (const char*)input_items[0];
74     char* out = (char*)output_items[0];
75 
76     size_t item_size = input_signature()->sizeof_stream_item(0);
77     int ni = 0;
78     int no = 0;
79 
80     while (ni < ninput_items[0] && no < noutput_items) {
81         d_count--;
82         if (d_count <= 0) {
83             memcpy(out, in, item_size); // copy 1 item
84             out += item_size;
85             no++;
86             d_count = d_n;
87         }
88         in += item_size;
89         ni++;
90     }
91 
92     // Because we have set TPP_DONT, we have to propagate the tags here manually.
93     // Adjustment of the tag sample value is done using the float d_decim_rate.
94     std::vector<tag_t> tags;
95     std::vector<tag_t>::iterator t;
96     get_tags_in_range(tags, 0, nitems_read(0), nitems_read(0) + ni);
97     for (t = tags.begin(); t != tags.end(); t++) {
98         tag_t new_tag = *t;
99         new_tag.offset *= d_decim_rate;
100         add_item_tag(0, new_tag);
101     }
102 
103     consume_each(ni);
104     return no;
105 }
106 
107 } /* namespace blocks */
108 } /* namespace gr */
109