~ubuntu-branches/ubuntu/trusty/gnuradio/trusty-updates

« back to all changes in this revision

Viewing changes to .pc/0024-io-fix-triggering-and-performance-issues-with-oscope.patch/gnuradio-core/src/lib/io/gr_oscope_guts.cc

  • Committer: Package Import Robot
  • Author(s): A. Maitland Bottoms
  • Date: 2012-02-26 21:26:16 UTC
  • mfrom: (1.1.4)
  • Revision ID: package-import@ubuntu.com-20120226212616-vsfkbi1158xshdql
Tags: 3.5.1-1
* new upstream version, re-packaged from scratch with modern tools
    closes: #642716, #645332, #394849, #616832, #590048, #642580,
    #647018, #557050, #559640, #631863
* CMake build

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- c++ -*- */
 
2
/*
 
3
 * Copyright 2003,2005 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
#include <gr_oscope_guts.h>
 
27
#include <stdexcept>
 
28
#include <stdio.h>
 
29
#include <algorithm>
 
30
#include <unistd.h>
 
31
#include <math.h>
 
32
#include <assert.h>
 
33
 
 
34
static const int OUTPUT_RECORD_SIZE = 16384;  // Must be power of 2
 
35
static inline int
 
36
wrap_bi (int buffer_index)                // wrap buffer index
 
37
{
 
38
  return buffer_index & (OUTPUT_RECORD_SIZE - 1);
 
39
}
 
40
 
 
41
static inline int
 
42
incr_bi (int buffer_index)                // increment buffer index
 
43
{
 
44
  return wrap_bi (buffer_index + 1);
 
45
}
 
46
 
 
47
static inline int
 
48
decr_bi (int buffer_index)                // decrement buffer index
 
49
{
 
50
  return wrap_bi (buffer_index - 1);
 
51
}
 
52
 
 
53
gr_oscope_guts::gr_oscope_guts (double sample_rate, gr_msg_queue_sptr msgq)
 
54
  : d_nchannels (1),
 
55
    d_msgq (msgq), 
 
56
    d_trigger_mode (gr_TRIG_MODE_AUTO),
 
57
    d_trigger_slope (gr_TRIG_SLOPE_POS),
 
58
    d_trigger_channel (0),
 
59
    d_sample_rate (sample_rate),
 
60
    d_update_rate (20),
 
61
    d_trigger_level (0),
 
62
    d_obi (0),
 
63
    d_state (HOLD_OFF),
 
64
    d_decimator_count (0),
 
65
    d_decimator_count_init (1),
 
66
    d_hold_off_count (0),
 
67
    d_hold_off_count_init (OUTPUT_RECORD_SIZE/2-1),
 
68
    d_pre_trigger_count (0),
 
69
    d_post_trigger_count (0),
 
70
    d_post_trigger_count_init (OUTPUT_RECORD_SIZE/2)
 
71
{
 
72
  for (int i = 0; i < MAX_CHANNELS; i++)
 
73
    d_buffer[i] = 0;
 
74
 
 
75
  for (int i = 0; i < MAX_CHANNELS; i++){
 
76
    d_buffer[i] = new float [OUTPUT_RECORD_SIZE];
 
77
    for (int j = 0; j < OUTPUT_RECORD_SIZE; j++)
 
78
      d_buffer[i][j] = 0.0;
 
79
  }
 
80
 
 
81
  // be sure buffer is full before first write
 
82
  enter_hold_off ();
 
83
  update_rate_or_decimation_changed ();
 
84
}
 
85
 
 
86
gr_oscope_guts::~gr_oscope_guts ()
 
87
{
 
88
  for (int i = 0; i < MAX_CHANNELS; i++)
 
89
    delete [] d_buffer[i];
 
90
}
 
91
 
 
92
// MANIPULATORS
 
93
 
 
94
// \p channel_data points to nchannels float values.  These are the values
 
95
// for each channel at this sample time.
 
96
 
 
97
void
 
98
gr_oscope_guts::process_sample (const float *channel_data)
 
99
{
 
100
  d_decimator_count--;
 
101
  if (d_decimator_count > 0)
 
102
    return;
 
103
 
 
104
  d_decimator_count = d_decimator_count_init;
 
105
  
 
106
  if (d_trigger_mode != gr_TRIG_MODE_STRIPCHART)
 
107
  {
 
108
          for (int i = 0; i < d_nchannels; i++)
 
109
                d_buffer[i][d_obi] = channel_data[i];                // copy data into buffer
 
110
 
 
111
          switch (d_state){
 
112
          case HOLD_OFF:
 
113
                d_hold_off_count--;
 
114
                if (d_hold_off_count <= 0)
 
115
                  enter_look_for_trigger ();
 
116
                break;
 
117
 
 
118
          case LOOK_FOR_TRIGGER:
 
119
                if (found_trigger ())
 
120
                  enter_post_trigger ();
 
121
                break;
 
122
 
 
123
          case POST_TRIGGER:
 
124
                d_post_trigger_count--;
 
125
                if (d_post_trigger_count <= 0){
 
126
                  write_output_records ();
 
127
                  enter_hold_off ();
 
128
                }
 
129
                break;
 
130
 
 
131
          default:
 
132
                assert (0);
 
133
          }
 
134
 
 
135
          d_obi = incr_bi (d_obi);
 
136
  }
 
137
  else
 
138
  {
 
139
          for (int i = 0; i < d_nchannels; i++)
 
140
          {
 
141
            for (int j = OUTPUT_RECORD_SIZE-1; j > 0; j--)
 
142
            {
 
143
                        d_buffer[i][j] = d_buffer[i][j-1];
 
144
                }
 
145
                d_buffer[i][0] = channel_data[i];
 
146
          }
 
147
          write_output_records();
 
148
  }
 
149
}
 
150
 
 
151
/*
 
152
 * Functions called on state entry
 
153
 */
 
154
 
 
155
void
 
156
gr_oscope_guts::enter_hold_off ()
 
157
{
 
158
  d_state = HOLD_OFF;
 
159
  d_hold_off_count = d_hold_off_count_init;
 
160
}
 
161
 
 
162
void
 
163
gr_oscope_guts::enter_look_for_trigger ()
 
164
{
 
165
  d_pre_trigger_count = 0;
 
166
  d_state = LOOK_FOR_TRIGGER;
 
167
}
 
168
 
 
169
void
 
170
gr_oscope_guts::enter_post_trigger ()
 
171
{
 
172
  d_state = POST_TRIGGER;
 
173
  d_post_trigger_count = d_post_trigger_count_init;
 
174
  //ensure that the trigger offset is no more than than half a sample
 
175
  if (d_trigger_off > .5) d_trigger_off -= 1;
 
176
  else d_post_trigger_count--;
 
177
}
 
178
 
 
179
// ----------------------------------------------------------------
 
180
// returns true if trigger found
 
181
 
 
182
bool
 
183
gr_oscope_guts::found_trigger ()
 
184
{
 
185
  float prev_sample = d_buffer[d_trigger_channel][decr_bi(d_obi)];
 
186
  float new_sample = d_buffer[d_trigger_channel][d_obi];
 
187
 
 
188
  switch (d_trigger_mode){
 
189
 
 
190
  case gr_TRIG_MODE_AUTO: //too many samples without a trigger
 
191
    d_pre_trigger_count++;
 
192
    if (d_pre_trigger_count > OUTPUT_RECORD_SIZE/2) return true;
 
193
 
 
194
  case gr_TRIG_MODE_NORM: //look for trigger
 
195
    switch (d_trigger_slope){
 
196
 
 
197
    case gr_TRIG_SLOPE_POS: //trigger point in pos slope?
 
198
      if (new_sample < d_trigger_level || prev_sample >= d_trigger_level) return false;
 
199
      break;
 
200
 
 
201
    case gr_TRIG_SLOPE_NEG: //trigger point in neg slope?
 
202
      if (new_sample > d_trigger_level || prev_sample <= d_trigger_level) return false;
 
203
      break;
 
204
    }
 
205
 
 
206
    //calculate the trigger offset in % sample
 
207
    d_trigger_off = (d_trigger_level - prev_sample)/(new_sample - prev_sample);
 
208
    return true;
 
209
 
 
210
  case gr_TRIG_MODE_FREE: //free run mode, always trigger
 
211
    d_trigger_off = 0;
 
212
    return true;
 
213
 
 
214
  default:
 
215
    assert (0);
 
216
    return false;
 
217
  }
 
218
}
 
219
 
 
220
// ----------------------------------------------------------------
 
221
// write output records (duh!)
 
222
 
 
223
void
 
224
gr_oscope_guts::write_output_records ()
 
225
{
 
226
  // if the output queue if full, drop the data like its hot.
 
227
  if (d_msgq->full_p())
 
228
    return;
 
229
    // Build a message to hold the output records
 
230
  gr_message_sptr msg = 
 
231
    gr_make_message(0,                                         // msg type
 
232
            d_nchannels,                                       // arg1 for other side
 
233
            OUTPUT_RECORD_SIZE,                                // arg2 for other side
 
234
            ((d_nchannels * OUTPUT_RECORD_SIZE) + 1) * sizeof(float)); // sizeof payload
 
235
 
 
236
  float *out = (float *)msg->msg();        // get pointer to raw message buffer
 
237
 
 
238
  for (int ch = 0; ch < d_nchannels; ch++){
 
239
    // note that d_obi + 1 points at the oldest sample in the buffer
 
240
    for (int i = 0; i < OUTPUT_RECORD_SIZE; i++){
 
241
      out[i] = d_buffer[ch][wrap_bi(d_obi + 1 + i)];
 
242
    }
 
243
    out += OUTPUT_RECORD_SIZE;
 
244
  }
 
245
  //Set the last sample as the trigger offset:
 
246
  //  The non gl scope sink will not look at this last sample.
 
247
  //  The gl scope sink will use this last sample as an offset.
 
248
  out[0] = d_trigger_off;
 
249
  d_msgq->handle(msg);                // send the msg
 
250
}
 
251
 
 
252
// ----------------------------------------------------------------
 
253
 
 
254
bool
 
255
gr_oscope_guts::set_update_rate (double update_rate)
 
256
{
 
257
  d_update_rate = std::min (std::max (1./10., update_rate), d_sample_rate);
 
258
  update_rate_or_decimation_changed ();
 
259
  return true;
 
260
}
 
261
 
 
262
bool
 
263
gr_oscope_guts::set_decimation_count (int decimator_count)
 
264
{
 
265
  decimator_count = std::max (1, decimator_count);
 
266
  d_decimator_count_init = decimator_count;
 
267
  update_rate_or_decimation_changed ();
 
268
  return true;
 
269
}
 
270
 
 
271
bool
 
272
gr_oscope_guts::set_sample_rate(double sample_rate)
 
273
{
 
274
  d_sample_rate = sample_rate;
 
275
  return set_update_rate(update_rate());
 
276
}
 
277
 
 
278
 
 
279
void
 
280
gr_oscope_guts::update_rate_or_decimation_changed ()
 
281
{
 
282
  d_hold_off_count_init =
 
283
    (int) rint (d_sample_rate / d_update_rate / d_decimator_count_init);
 
284
}
 
285
 
 
286
bool
 
287
gr_oscope_guts::set_trigger_channel (int channel)
 
288
{
 
289
  if (channel >= 0 && channel < d_nchannels){
 
290
    d_trigger_channel = channel;
 
291
    trigger_changed ();
 
292
    return true;
 
293
  }
 
294
 
 
295
  return false;
 
296
}
 
297
 
 
298
bool
 
299
gr_oscope_guts::set_trigger_mode (gr_trigger_mode mode)
 
300
{
 
301
  d_trigger_mode = mode;
 
302
  trigger_changed ();
 
303
  return true;
 
304
}
 
305
 
 
306
bool
 
307
gr_oscope_guts::set_trigger_slope (gr_trigger_slope slope)
 
308
{
 
309
  d_trigger_slope = slope;
 
310
  trigger_changed ();
 
311
  return true;
 
312
}
 
313
 
 
314
bool
 
315
gr_oscope_guts::set_trigger_level (double trigger_level)
 
316
{
 
317
  d_trigger_level = trigger_level;
 
318
  trigger_changed ();
 
319
  return true;
 
320
}
 
321
 
 
322
bool
 
323
gr_oscope_guts::set_trigger_level_auto ()
 
324
{
 
325
  // find the level 1/2 way between the min and the max
 
326
 
 
327
  float min_v = d_buffer[d_trigger_channel][0];
 
328
  float max_v = d_buffer[d_trigger_channel][0];
 
329
 
 
330
  for (int i = 1; i < OUTPUT_RECORD_SIZE; i++){
 
331
    min_v = std::min (min_v, d_buffer[d_trigger_channel][i]);
 
332
    max_v = std::max (max_v, d_buffer[d_trigger_channel][i]);
 
333
  }
 
334
  return set_trigger_level((min_v + max_v) * 0.5);
 
335
}
 
336
 
 
337
bool
 
338
gr_oscope_guts::set_num_channels(int nchannels)
 
339
{
 
340
  if (nchannels > 0 && nchannels <= MAX_CHANNELS){
 
341
    d_nchannels = nchannels;
 
342
    return true;
 
343
  }
 
344
  return false;
 
345
}
 
346
 
 
347
 
 
348
void
 
349
gr_oscope_guts::trigger_changed ()
 
350
{
 
351
  enter_look_for_trigger ();
 
352
}
 
353
 
 
354
// ACCESSORS
 
355
 
 
356
int
 
357
gr_oscope_guts::num_channels () const
 
358
{
 
359
  return d_nchannels;
 
360
}
 
361
 
 
362
double
 
363
gr_oscope_guts::sample_rate () const
 
364
{
 
365
  return d_sample_rate;
 
366
}
 
367
 
 
368
double
 
369
gr_oscope_guts::update_rate () const
 
370
{
 
371
  return d_update_rate;
 
372
}
 
373
 
 
374
int
 
375
gr_oscope_guts::get_decimation_count () const
 
376
{
 
377
  return d_decimator_count_init;
 
378
}
 
379
 
 
380
int
 
381
gr_oscope_guts::get_trigger_channel () const
 
382
{
 
383
  return d_trigger_channel;
 
384
}
 
385
 
 
386
gr_trigger_mode
 
387
gr_oscope_guts::get_trigger_mode () const
 
388
{
 
389
  return d_trigger_mode;
 
390
}
 
391
 
 
392
gr_trigger_slope
 
393
gr_oscope_guts::get_trigger_slope () const
 
394
{
 
395
  return d_trigger_slope;
 
396
}
 
397
 
 
398
double
 
399
gr_oscope_guts::get_trigger_level () const
 
400
{
 
401
  return d_trigger_level;
 
402
}
 
403
 
 
404
int
 
405
gr_oscope_guts::get_samples_per_output_record () const
 
406
{
 
407
  return OUTPUT_RECORD_SIZE;
 
408
}