1 /* -*- c++ -*- */
2 /*
3 * Copyright 2012,2013,2015 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 "time_raster_sink_f_impl.h"
28
29 #include <gnuradio/io_signature.h>
30 #include <gnuradio/prefs.h>
31
32 #include <volk/volk.h>
33
34 #include <string.h>
35
36 namespace gr {
37 namespace qtgui {
38
make(double samp_rate,double rows,double cols,const std::vector<float> & mult,const std::vector<float> & offset,const std::string & name,int nconnections,QWidget * parent)39 time_raster_sink_f::sptr time_raster_sink_f::make(double samp_rate,
40 double rows,
41 double cols,
42 const std::vector<float>& mult,
43 const std::vector<float>& offset,
44 const std::string& name,
45 int nconnections,
46 QWidget* parent)
47 {
48 return gnuradio::get_initial_sptr(new time_raster_sink_f_impl(
49 samp_rate, rows, cols, mult, offset, name, nconnections, parent));
50 }
51
time_raster_sink_f_impl(double samp_rate,double rows,double cols,const std::vector<float> & mult,const std::vector<float> & offset,const std::string & name,int nconnections,QWidget * parent)52 time_raster_sink_f_impl::time_raster_sink_f_impl(double samp_rate,
53 double rows,
54 double cols,
55 const std::vector<float>& mult,
56 const std::vector<float>& offset,
57 const std::string& name,
58 int nconnections,
59 QWidget* parent)
60 : sync_block("time_raster_sink_f",
61 io_signature::make(0, nconnections, sizeof(float)),
62 io_signature::make(0, 0, 0)),
63 d_name(name),
64 d_nconnections(nconnections),
65 d_parent(parent),
66 d_rows(rows),
67 d_cols(cols),
68 d_mult(std::vector<float>(nconnections + 1, 1)),
69 d_offset(std::vector<float>(nconnections + 1, 0)),
70 d_samp_rate(samp_rate)
71 {
72 // Required now for Qt; argc must be greater than 0 and argv
73 // must have at least one valid character. Must be valid through
74 // life of the qApplication:
75 // http://harmattan-dev.nokia.com/docs/library/html/qt4/qapplication.html
76 d_argc = 1;
77 d_argv = new char;
78 d_argv[0] = '\0';
79
80 d_main_gui = NULL;
81
82 d_index = 0;
83
84 // setup PDU handling input port
85 message_port_register_in(pmt::mp("in"));
86 set_msg_handler(pmt::mp("in"), [this](pmt::pmt_t msg) { this->handle_pdus(msg); });
87
88 d_icols = static_cast<int>(ceil(d_cols));
89 d_tmpflt = (float*)volk_malloc(d_icols * sizeof(float), volk_get_alignment());
90 memset(d_tmpflt, 0, d_icols * sizeof(float));
91
92 // +1 for the PDU buffer
93 for (int i = 0; i < d_nconnections + 1; i++) {
94 d_residbufs.push_back(
95 (double*)volk_malloc(d_icols * sizeof(double), volk_get_alignment()));
96 memset(d_residbufs[i], 0, d_icols * sizeof(double));
97 }
98
99 set_multiplier(mult);
100 set_offset(offset);
101
102 initialize();
103 }
104
~time_raster_sink_f_impl()105 time_raster_sink_f_impl::~time_raster_sink_f_impl()
106 {
107 if (!d_main_gui->isClosed())
108 d_main_gui->close();
109
110 volk_free(d_tmpflt);
111 for (int i = 0; i < d_nconnections + 1; i++) {
112 volk_free(d_residbufs[i]);
113 }
114
115 delete d_argv;
116 }
117
check_topology(int ninputs,int noutputs)118 bool time_raster_sink_f_impl::check_topology(int ninputs, int noutputs)
119 {
120 return ninputs == d_nconnections;
121 }
122
initialize()123 void time_raster_sink_f_impl::initialize()
124 {
125 if (qApp != NULL) {
126 d_qApplication = qApp;
127 } else {
128 #if QT_VERSION >= 0x040500 && QT_VERSION < 0x050000
129 std::string style = prefs::singleton()->get_string("qtgui", "style", "raster");
130 QApplication::setGraphicsSystem(QString(style.c_str()));
131 #endif
132 d_qApplication = new QApplication(d_argc, &d_argv);
133 }
134
135 // If a style sheet is set in the prefs file, enable it here.
136 check_set_qss(d_qApplication);
137
138 // Create time raster plot; as a bit input, we expect to see 1's
139 // and 0's from each stream, so we set the maximum intensity
140 // (zmax) to the number of connections so after adding the
141 // streams, the max will the the max of 1's from all streams.
142 int numplots = (d_nconnections > 0) ? d_nconnections : 1;
143 d_main_gui =
144 new TimeRasterDisplayForm(numplots, d_samp_rate, d_rows, d_cols, 1, d_parent);
145
146 if (!d_name.empty())
147 set_title(d_name);
148
149 // initialize update time to 10 times a second
150 set_update_time(0.1);
151 }
152
exec_()153 void time_raster_sink_f_impl::exec_() { d_qApplication->exec(); }
154
qwidget()155 QWidget* time_raster_sink_f_impl::qwidget() { return d_main_gui; }
156
157 #ifdef ENABLE_PYTHON
pyqwidget()158 PyObject* time_raster_sink_f_impl::pyqwidget()
159 {
160 PyObject* w = PyLong_FromVoidPtr((void*)d_main_gui);
161 PyObject* retarg = Py_BuildValue("N", w);
162 return retarg;
163 }
164 #else
pyqwidget()165 void* time_raster_sink_f_impl::pyqwidget() { return NULL; }
166 #endif
167
set_update_time(double t)168 void time_raster_sink_f_impl::set_update_time(double t)
169 {
170 // convert update time to ticks
171 gr::high_res_timer_type tps = gr::high_res_timer_tps();
172 d_update_time = t * tps;
173 d_main_gui->setUpdateTime(t);
174 d_last_time = 0;
175 }
176
set_title(const std::string & title)177 void time_raster_sink_f_impl::set_title(const std::string& title)
178 {
179 d_main_gui->setTitle(title.c_str());
180 }
181
set_line_label(unsigned int which,const std::string & label)182 void time_raster_sink_f_impl::set_line_label(unsigned int which, const std::string& label)
183 {
184 d_main_gui->setLineLabel(which, label.c_str());
185 }
186
set_line_color(unsigned int which,const std::string & color)187 void time_raster_sink_f_impl::set_line_color(unsigned int which, const std::string& color)
188 {
189 d_main_gui->setLineColor(which, color.c_str());
190 }
191
set_line_width(unsigned int which,int width)192 void time_raster_sink_f_impl::set_line_width(unsigned int which, int width)
193 {
194 d_main_gui->setLineWidth(which, width);
195 }
196
set_line_style(unsigned int which,Qt::PenStyle style)197 void time_raster_sink_f_impl::set_line_style(unsigned int which, Qt::PenStyle style)
198 {
199 d_main_gui->setLineStyle(which, style);
200 }
201
set_line_marker(unsigned int which,QwtSymbol::Style marker)202 void time_raster_sink_f_impl::set_line_marker(unsigned int which, QwtSymbol::Style marker)
203 {
204 d_main_gui->setLineMarker(which, marker);
205 }
206
set_color_map(unsigned int which,const int color)207 void time_raster_sink_f_impl::set_color_map(unsigned int which, const int color)
208 {
209 d_main_gui->setColorMap(which, color);
210 }
211
set_line_alpha(unsigned int which,double alpha)212 void time_raster_sink_f_impl::set_line_alpha(unsigned int which, double alpha)
213 {
214 d_main_gui->setAlpha(which, (int)(255.0 * alpha));
215 }
216
set_size(int width,int height)217 void time_raster_sink_f_impl::set_size(int width, int height)
218 {
219 d_main_gui->resize(QSize(width, height));
220 }
221
set_samp_rate(const double samp_rate)222 void time_raster_sink_f_impl::set_samp_rate(const double samp_rate)
223 {
224 d_samp_rate = samp_rate;
225 d_main_gui->setSampleRate(d_samp_rate);
226 }
227
set_num_rows(double rows)228 void time_raster_sink_f_impl::set_num_rows(double rows)
229 {
230 gr::thread::scoped_lock lock(d_setlock);
231 d_rows = rows;
232 d_main_gui->setNumRows(rows);
233 }
234
set_num_cols(double cols)235 void time_raster_sink_f_impl::set_num_cols(double cols)
236 {
237 if (d_cols != cols) {
238 gr::thread::scoped_lock lock(d_setlock);
239
240 d_qApplication->postEvent(d_main_gui, new TimeRasterSetSize(d_rows, cols));
241
242 d_cols = cols;
243 d_icols = static_cast<int>(ceil(d_cols));
244
245 volk_free(d_tmpflt);
246 d_tmpflt = (float*)volk_malloc(d_icols * sizeof(float), volk_get_alignment());
247 memset(d_tmpflt, 0, d_icols * sizeof(float));
248
249 for (int i = 0; i < d_nconnections + 1; i++) {
250 volk_free(d_residbufs[i]);
251 d_residbufs[i] =
252 (double*)volk_malloc(d_icols * sizeof(double), volk_get_alignment());
253 memset(d_residbufs[i], 0, d_icols * sizeof(double));
254 }
255 reset();
256 }
257 }
258
title()259 std::string time_raster_sink_f_impl::title() { return d_main_gui->title().toStdString(); }
260
line_label(unsigned int which)261 std::string time_raster_sink_f_impl::line_label(unsigned int which)
262 {
263 return d_main_gui->lineLabel(which).toStdString();
264 }
265
line_color(unsigned int which)266 std::string time_raster_sink_f_impl::line_color(unsigned int which)
267 {
268 return d_main_gui->lineColor(which).toStdString();
269 }
270
line_width(unsigned int which)271 int time_raster_sink_f_impl::line_width(unsigned int which)
272 {
273 return d_main_gui->lineWidth(which);
274 }
275
line_style(unsigned int which)276 int time_raster_sink_f_impl::line_style(unsigned int which)
277 {
278 return d_main_gui->lineStyle(which);
279 }
280
line_marker(unsigned int which)281 int time_raster_sink_f_impl::line_marker(unsigned int which)
282 {
283 return d_main_gui->lineMarker(which);
284 }
285
color_map(unsigned int which)286 int time_raster_sink_f_impl::color_map(unsigned int which)
287 {
288 return d_main_gui->getColorMap(which);
289 }
290
line_alpha(unsigned int which)291 double time_raster_sink_f_impl::line_alpha(unsigned int which)
292 {
293 return (double)(d_main_gui->markerAlpha(which)) / 255.0;
294 }
295
num_rows()296 double time_raster_sink_f_impl::num_rows() { return d_main_gui->numRows(); }
297
num_cols()298 double time_raster_sink_f_impl::num_cols() { return d_main_gui->numCols(); }
299
set_multiplier(const std::vector<float> & mult)300 void time_raster_sink_f_impl::set_multiplier(const std::vector<float>& mult)
301 {
302 if (mult.empty()) {
303 for (int i = 0; i < d_nconnections; i++) {
304 d_mult[i] = 1.0f;
305 }
306 } else if (mult.size() == (size_t)d_nconnections) {
307 for (int i = 0; i < d_nconnections; i++) {
308 d_mult[i] = mult[i];
309 }
310 } else {
311 throw std::runtime_error(
312 "time_raster_sink_f_impl::set_multiplier incorrect dimensions.\n");
313 }
314 }
315
set_offset(const std::vector<float> & offset)316 void time_raster_sink_f_impl::set_offset(const std::vector<float>& offset)
317 {
318 if (offset.empty()) {
319 for (int i = 0; i < d_nconnections; i++) {
320 d_offset[i] = 0.0f;
321 }
322 } else if (offset.size() == (size_t)d_nconnections) {
323 for (int i = 0; i < d_nconnections; i++) {
324 d_offset[i] = offset[i];
325 }
326 } else {
327 throw std::runtime_error(
328 "time_raster_sink_f_impl::set_offset incorrect dimensions.\n");
329 }
330 }
331
set_intensity_range(float min,float max)332 void time_raster_sink_f_impl::set_intensity_range(float min, float max)
333 {
334 d_main_gui->setIntensityRange(min, max);
335 }
336
enable_menu(bool en)337 void time_raster_sink_f_impl::enable_menu(bool en) { d_main_gui->enableMenu(en); }
338
enable_grid(bool en)339 void time_raster_sink_f_impl::enable_grid(bool en) { d_main_gui->setGrid(en); }
340
enable_axis_labels(bool en)341 void time_raster_sink_f_impl::enable_axis_labels(bool en)
342 {
343 d_main_gui->setAxisLabels(en);
344 }
345
enable_autoscale(bool en)346 void time_raster_sink_f_impl::enable_autoscale(bool en) { d_main_gui->autoScale(en); }
347
reset()348 void time_raster_sink_f_impl::reset() { d_index = 0; }
349
_ncols_resize()350 void time_raster_sink_f_impl::_ncols_resize()
351 {
352 double cols = d_main_gui->numCols();
353 set_num_cols(cols);
354 }
355
work(int noutput_items,gr_vector_const_void_star & input_items,gr_vector_void_star & output_items)356 int time_raster_sink_f_impl::work(int noutput_items,
357 gr_vector_const_void_star& input_items,
358 gr_vector_void_star& output_items)
359 {
360 int n = 0, j = 0, idx = 0;
361 const float* in = (const float*)input_items[0];
362
363 _ncols_resize();
364
365 for (int i = 0; i < noutput_items; i += d_icols) {
366 unsigned int datasize = noutput_items - i;
367 unsigned int resid = d_icols - d_index;
368 idx = 0;
369
370 // If we have enough input for one full plot, do it
371 if (datasize >= resid) {
372
373 // Fill up residbufs with d_size number of items
374 for (n = 0; n < d_nconnections; n++) {
375 in = (const float*)input_items[idx++];
376
377 // Scale and add offset
378 volk_32f_s32f_multiply_32f(d_tmpflt, &in[j], d_mult[n], resid);
379 for (unsigned int s = 0; s < resid; s++)
380 d_tmpflt[s] = d_tmpflt[s] + d_offset[n];
381
382 volk_32f_convert_64f_u(&d_residbufs[n][d_index], d_tmpflt, resid);
383 }
384
385 // Update the plot if its time
386 if (gr::high_res_timer_now() - d_last_time > d_update_time) {
387 d_last_time = gr::high_res_timer_now();
388 d_qApplication->postEvent(d_main_gui,
389 new TimeRasterUpdateEvent(d_residbufs, d_cols));
390 }
391
392 d_index = 0;
393 j += resid;
394 }
395 // Otherwise, copy what we received into the residbufs for next time
396 // because we set the output_multiple, this should never need to be called
397 else {
398 for (n = 0; n < d_nconnections; n++) {
399 in = (const float*)input_items[idx++];
400
401 // Scale and add offset
402 volk_32f_s32f_multiply_32f(d_tmpflt, &in[j], d_mult[n], datasize);
403 for (unsigned int s = 0; s < datasize; s++)
404 d_tmpflt[s] = d_tmpflt[s] + d_offset[n];
405
406 volk_32f_convert_64f(&d_residbufs[n][d_index], d_tmpflt, datasize);
407 }
408 d_index += datasize;
409 j += datasize;
410 }
411 }
412
413 return j;
414 }
415
handle_pdus(pmt::pmt_t msg)416 void time_raster_sink_f_impl::handle_pdus(pmt::pmt_t msg)
417 {
418 size_t len;
419 pmt::pmt_t dict, samples;
420
421 // Test to make sure this is either a PDU or a uniform vector of
422 // samples. Get the samples PMT and the dictionary if it's a PDU.
423 // If not, we throw an error and exit.
424 if (pmt::is_pair(msg)) {
425 dict = pmt::car(msg);
426 samples = pmt::cdr(msg);
427 } else if (pmt::is_uniform_vector(msg)) {
428 samples = msg;
429 } else {
430 throw std::runtime_error("time_sink_c: message must be either "
431 "a PDU or a uniform vector of samples.");
432 }
433
434 len = pmt::length(samples);
435
436 const float* in;
437 if (pmt::is_f32vector(samples)) {
438 in = (const float*)pmt::f32vector_elements(samples, len);
439 } else {
440 throw std::runtime_error("time_raster_sink_f: unknown data type "
441 "of samples; must be float.");
442 }
443
444 // Plot if we're past the last update time
445 if (gr::high_res_timer_now() - d_last_time > d_update_time) {
446 d_last_time = gr::high_res_timer_now();
447
448 _ncols_resize();
449
450 d_rows = ceil(static_cast<double>(len) / static_cast<double>(d_cols));
451 int irows = static_cast<int>(d_rows);
452
453 d_qApplication->postEvent(d_main_gui, new TimeRasterSetSize(d_rows, d_cols));
454
455 int idx = 0;
456 for (int r = 0; r < irows; r++) {
457 // Scale and add offset
458 int cpy_len = std::min(static_cast<size_t>(d_cols), len - idx);
459 memset(d_residbufs[d_nconnections], 0, d_cols * sizeof(double));
460 volk_32f_s32f_multiply_32f(
461 d_tmpflt, &in[idx], d_mult[d_nconnections], cpy_len);
462 for (int c = 0; c < cpy_len; c++) {
463 d_tmpflt[c] = d_tmpflt[c] + d_offset[d_nconnections];
464 }
465
466 volk_32f_convert_64f_u(d_residbufs[d_nconnections], d_tmpflt, cpy_len);
467
468 d_qApplication->postEvent(d_main_gui,
469 new TimeRasterUpdateEvent(d_residbufs, d_cols));
470 idx += d_cols;
471 }
472 }
473 }
474
475 } /* namespace qtgui */
476 } /* namespace gr */
477