1 /* -*- c++ -*- */
2 /*
3  * Copyright 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 "selector_impl.h"
28 #include <gnuradio/io_signature.h>
29 #include <string.h>
30 #include <stdexcept>
31 
32 namespace gr {
33 namespace blocks {
34 
35 selector::sptr
make(size_t itemsize,unsigned int input_index,unsigned int output_index)36 selector::make(size_t itemsize, unsigned int input_index, unsigned int output_index)
37 {
38     return gnuradio::get_initial_sptr(
39         new selector_impl(itemsize, input_index, output_index));
40 }
41 
selector_impl(size_t itemsize,unsigned int input_index,unsigned int output_index)42 selector_impl::selector_impl(size_t itemsize,
43                              unsigned int input_index,
44                              unsigned int output_index)
45     : block("selector",
46             io_signature::make(1, -1, itemsize),
47             io_signature::make(1, -1, itemsize)),
48       d_itemsize(itemsize),
49       d_enabled(true),
50       d_input_index(input_index),
51       d_output_index(output_index),
52       d_num_inputs(0),
53       d_num_outputs(0)
54 {
55     message_port_register_in(pmt::mp("en"));
56     set_msg_handler(pmt::mp("en"), [this](pmt::pmt_t msg) { this->handle_enable(msg); });
57 
58     // TODO: add message ports for input_index and output_index
59 }
60 
~selector_impl()61 selector_impl::~selector_impl() {}
62 
set_input_index(unsigned int input_index)63 void selector_impl::set_input_index(unsigned int input_index)
64 {
65     gr::thread::scoped_lock l(d_mutex);
66     if (input_index < d_num_inputs)
67         d_input_index = input_index;
68     else
69         throw std::out_of_range("input_index must be < ninputs");
70 }
71 
set_output_index(unsigned int output_index)72 void selector_impl::set_output_index(unsigned int output_index)
73 {
74     gr::thread::scoped_lock l(d_mutex);
75     if (output_index < d_num_outputs)
76         d_output_index = output_index;
77     else
78         throw std::out_of_range("output_index must be < noutputs");
79 }
80 
handle_enable(pmt::pmt_t msg)81 void selector_impl::handle_enable(pmt::pmt_t msg)
82 {
83     if (pmt::is_bool(msg)) {
84         bool en = pmt::to_bool(msg);
85         gr::thread::scoped_lock l(d_mutex);
86         d_enabled = en;
87     } else {
88         GR_LOG_WARN(d_logger,
89                     "handle_enable: Non-PMT type received, expecting Boolean PMT");
90     }
91 }
92 
forecast(int noutput_items,gr_vector_int & ninput_items_required)93 void selector_impl::forecast(int noutput_items, gr_vector_int& ninput_items_required)
94 {
95     unsigned ninputs = ninput_items_required.size();
96     for (unsigned i = 0; i < ninputs; i++) {
97         ninput_items_required[i] = 0;
98     }
99     ninput_items_required[d_input_index] = noutput_items;
100 }
101 
check_topology(int ninputs,int noutputs)102 bool selector_impl::check_topology(int ninputs, int noutputs)
103 {
104     if ((int)d_input_index < ninputs && (int)d_output_index < noutputs) {
105         d_num_inputs = (unsigned int)ninputs;
106         d_num_outputs = (unsigned int)noutputs;
107         return true;
108     } else {
109         GR_LOG_WARN(d_logger,
110                     "check_topology: Input or Output index greater than number of ports");
111         return false;
112     }
113 }
114 
general_work(int noutput_items,gr_vector_int & ninput_items,gr_vector_const_void_star & input_items,gr_vector_void_star & output_items)115 int selector_impl::general_work(int noutput_items,
116                                 gr_vector_int& ninput_items,
117                                 gr_vector_const_void_star& input_items,
118                                 gr_vector_void_star& output_items)
119 {
120     const uint8_t** in = (const uint8_t**)&input_items[0];
121     uint8_t** out = (uint8_t**)&output_items[0];
122 
123     gr::thread::scoped_lock l(d_mutex);
124     if (d_enabled) {
125         std::copy(in[d_input_index],
126                   in[d_input_index] + noutput_items * d_itemsize,
127                   out[d_output_index]);
128         produce(d_output_index, noutput_items);
129     }
130 
131     consume_each(noutput_items);
132     return WORK_CALLED_PRODUCE;
133 }
134 
setup_rpc()135 void selector_impl::setup_rpc()
136 {
137 #ifdef GR_CTRLPORT
138     add_rpc_variable(rpcbasic_sptr(new rpcbasic_register_handler<selector>(
139         alias(), "en", "", "Enable", RPC_PRIVLVL_MIN, DISPNULL)));
140 #endif /* GR_CTRLPORT */
141 }
142 
143 } /* namespace blocks */
144 } /* namespace gr */
145