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