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