1 /* -*- c++ -*- */
2 /*
3  * Copyright 2014 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 "number_sink_impl.h"
28 
29 #include <gnuradio/fft/fft.h>
30 #include <gnuradio/io_signature.h>
31 
32 #include <qwt_symbol.h>
33 #include <volk/volk.h>
34 
35 #include <string.h>
36 #include <cmath>
37 
38 #ifdef _MSC_VER
39 #define isfinite _finite
40 
41 #include <float.h>
42 namespace std {
43 using ::_finite;
44 }
45 #endif
46 
47 namespace gr {
48 namespace qtgui {
49 
make(size_t itemsize,float average,graph_t graph_type,int nconnections,QWidget * parent)50 number_sink::sptr number_sink::make(
51     size_t itemsize, float average, graph_t graph_type, int nconnections, QWidget* parent)
52 {
53     return gnuradio::get_initial_sptr(
54         new number_sink_impl(itemsize, average, graph_type, nconnections, parent));
55 }
56 
number_sink_impl(size_t itemsize,float average,graph_t graph_type,int nconnections,QWidget * parent)57 number_sink_impl::number_sink_impl(
58     size_t itemsize, float average, graph_t graph_type, int nconnections, QWidget* parent)
59     : sync_block("number_sink",
60                  io_signature::make(nconnections, nconnections, itemsize),
61                  io_signature::make(0, 0, 0)),
62       d_itemsize(itemsize),
63       d_average(average),
64       d_type(graph_type),
65       d_nconnections(nconnections),
66       d_parent(parent),
67       d_avg_value(nconnections),
68       d_iir(nconnections)
69 {
70     for (int n = 0; n < d_nconnections; n++) {
71         d_avg_value[n] = 0;
72         d_iir[n].set_taps(d_average);
73     }
74 
75     // Required now for Qt; argc must be greater than 0 and argv
76     // must have at least one valid character. Must be valid through
77     // life of the qApplication:
78     // http://harmattan-dev.nokia.com/docs/library/html/qt4/qapplication.html
79     d_argc = 1;
80     d_argv = new char;
81     d_argv[0] = '\0';
82 
83     d_main_gui = NULL;
84 
85     // Set alignment properties for VOLK
86     const int alignment_multiple = volk_get_alignment() / d_itemsize;
87     set_alignment(std::max(1, alignment_multiple));
88 
89     initialize();
90 }
91 
~number_sink_impl()92 number_sink_impl::~number_sink_impl() {}
93 
check_topology(int ninputs,int noutputs)94 bool number_sink_impl::check_topology(int ninputs, int noutputs)
95 {
96     return ninputs == d_nconnections;
97 }
98 
initialize()99 void number_sink_impl::initialize()
100 {
101     if (qApp != NULL) {
102         d_qApplication = qApp;
103     } else {
104         d_qApplication = new QApplication(d_argc, &d_argv);
105     }
106 
107     d_main_gui = new NumberDisplayForm(d_nconnections, d_type, d_parent);
108     d_main_gui->setAverage(d_average);
109 
110     // initialize update time to 10 times a second
111     set_update_time(0.1);
112 }
113 
exec_()114 void number_sink_impl::exec_() { d_qApplication->exec(); }
115 
qwidget()116 QWidget* number_sink_impl::qwidget() { return d_main_gui; }
117 
118 #ifdef ENABLE_PYTHON
pyqwidget()119 PyObject* number_sink_impl::pyqwidget()
120 {
121     PyObject* w = PyLong_FromVoidPtr((void*)d_main_gui);
122     PyObject* retarg = Py_BuildValue("N", w);
123     return retarg;
124 }
125 #else
pyqwidget()126 void* number_sink_impl::pyqwidget() { return NULL; }
127 #endif
128 
set_update_time(double t)129 void number_sink_impl::set_update_time(double t)
130 {
131     // convert update time to ticks
132     gr::high_res_timer_type tps = gr::high_res_timer_tps();
133     d_main_gui->setUpdateTime(t);
134     d_update_time = t * tps;
135     d_last_time = 0;
136 }
137 
set_average(const float avg)138 void number_sink_impl::set_average(const float avg)
139 {
140     d_average = avg;
141     for (int n = 0; n < d_nconnections; n++) {
142         d_avg_value[n] = 0;
143         d_iir[n].set_taps(d_average);
144     }
145     d_main_gui->setAverage(avg);
146 }
147 
set_graph_type(const graph_t type)148 void number_sink_impl::set_graph_type(const graph_t type)
149 {
150     d_main_gui->setGraphType(type);
151 }
152 
set_color(unsigned int which,const std::string & min,const std::string & max)153 void number_sink_impl::set_color(unsigned int which,
154                                  const std::string& min,
155                                  const std::string& max)
156 {
157     d_main_gui->setColor(which, QColor(min.c_str()), QColor(max.c_str()));
158 }
159 
set_color(unsigned int which,int min,int max)160 void number_sink_impl::set_color(unsigned int which, int min, int max)
161 {
162     d_main_gui->setColor(which, QColor(min), QColor(max));
163 }
164 
set_label(unsigned int which,const std::string & label)165 void number_sink_impl::set_label(unsigned int which, const std::string& label)
166 {
167     d_main_gui->setLabel(which, label);
168 }
169 
set_min(unsigned int which,float min)170 void number_sink_impl::set_min(unsigned int which, float min)
171 {
172     d_main_gui->setScaleMin(which, min);
173 }
174 
set_max(unsigned int which,float max)175 void number_sink_impl::set_max(unsigned int which, float max)
176 {
177     d_main_gui->setScaleMax(which, max);
178 }
179 
set_title(const std::string & title)180 void number_sink_impl::set_title(const std::string& title)
181 {
182     d_main_gui->setTitle(title);
183 }
184 
set_unit(unsigned int which,const std::string & unit)185 void number_sink_impl::set_unit(unsigned int which, const std::string& unit)
186 {
187     d_main_gui->setUnit(which, unit);
188 }
189 
set_factor(unsigned int which,float factor)190 void number_sink_impl::set_factor(unsigned int which, float factor)
191 {
192     d_main_gui->setFactor(which, factor);
193 }
194 
average() const195 float number_sink_impl::average() const { return d_average; }
196 
graph_type() const197 graph_t number_sink_impl::graph_type() const { return d_main_gui->graphType(); }
198 
color_min(unsigned int which) const199 std::string number_sink_impl::color_min(unsigned int which) const
200 {
201     return d_main_gui->colorMin(which).name().toStdString();
202 }
203 
color_max(unsigned int which) const204 std::string number_sink_impl::color_max(unsigned int which) const
205 {
206     return d_main_gui->colorMax(which).name().toStdString();
207 }
208 
label(unsigned int which) const209 std::string number_sink_impl::label(unsigned int which) const
210 {
211     return d_main_gui->label(which);
212 }
213 
min(unsigned int which) const214 float number_sink_impl::min(unsigned int which) const
215 {
216     return d_main_gui->scaleMin(which);
217 }
218 
max(unsigned int which) const219 float number_sink_impl::max(unsigned int which) const
220 {
221     return d_main_gui->scaleMax(which);
222 }
223 
title() const224 std::string number_sink_impl::title() const { return d_main_gui->title(); }
225 
unit(unsigned int which) const226 std::string number_sink_impl::unit(unsigned int which) const
227 {
228     return d_main_gui->unit(which);
229 }
230 
factor(unsigned int which) const231 float number_sink_impl::factor(unsigned int which) const
232 {
233     return d_main_gui->factor(which);
234 }
235 
enable_menu(bool en)236 void number_sink_impl::enable_menu(bool en)
237 {
238     // d_main_gui->enableMenu(en);
239 }
240 
enable_autoscale(bool en)241 void number_sink_impl::enable_autoscale(bool en) { d_main_gui->autoScale(en); }
242 
reset()243 void number_sink_impl::reset()
244 {
245     gr::thread::scoped_lock lock(d_setlock);
246     _reset();
247 }
248 
_reset()249 void number_sink_impl::_reset() {}
250 
_gui_update_trigger()251 void number_sink_impl::_gui_update_trigger()
252 {
253     // Only update the time if different than the current interval
254     // add some slop in cpu ticks for double comparison
255     gr::high_res_timer_type tps = gr::high_res_timer_tps();
256     double t = d_main_gui->updateTime();
257     if ((d_update_time < (tps * t - 10)) || ((tps * t + 10) < d_update_time)) {
258         set_update_time(t);
259     }
260 
261     float a = d_main_gui->average();
262     if (a != d_average) {
263         set_average(a);
264     }
265 }
266 
get_item(const void * input_items,int n)267 float number_sink_impl::get_item(const void* input_items, int n)
268 {
269     char* inc;
270     short* ins;
271     float* inf;
272 
273     switch (d_itemsize) {
274     case (1):
275         inc = (char*)input_items;
276         return static_cast<float>(inc[n]);
277         break;
278     case (2):
279         ins = (short*)input_items;
280         return static_cast<float>(ins[n]);
281         break;
282     case (4):
283         inf = (float*)input_items;
284         return static_cast<float>(inf[n]);
285         break;
286     default:
287         throw std::runtime_error("item size not supported");
288     }
289     return 0;
290 }
291 
work(int noutput_items,gr_vector_const_void_star & input_items,gr_vector_void_star & output_items)292 int number_sink_impl::work(int noutput_items,
293                            gr_vector_const_void_star& input_items,
294                            gr_vector_void_star& output_items)
295 {
296     gr::thread::scoped_lock lock(d_setlock);
297 
298     _gui_update_trigger();
299 
300     if (d_average > 0) {
301         for (int n = 0; n < d_nconnections; n++) {
302             for (int i = 0; i < noutput_items; i++) {
303                 float x = get_item(input_items[n], i);
304                 if (std::isfinite(x))
305                     d_avg_value[n] = d_iir[n].filter(x);
306             }
307         }
308     }
309 
310     // Plot if we are able to update
311     if ((gr::high_res_timer_now() - d_last_time) > d_update_time) {
312         d_last_time = gr::high_res_timer_now();
313         std::vector<float> d(d_nconnections);
314         if (d_average > 0) {
315             for (int n = 0; n < d_nconnections; n++)
316                 d[n] = d_avg_value[n];
317         } else {
318             for (int n = 0; n < d_nconnections; n++) {
319                 float x = get_item(input_items[n], 0);
320                 if (std::isfinite(x))
321                     d[n] = x;
322             }
323         }
324         d_qApplication->postEvent(d_main_gui, new NumberUpdateEvent(d));
325     }
326 
327     return noutput_items;
328     ;
329 }
330 
331 } /* namespace qtgui */
332 } /* namespace gr */
333