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