3
* Copyright 2003,2005 Free Software Foundation, Inc.
5
* This file is part of GNU Radio
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)
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.
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.
26
#include <gr_oscope_guts.h>
34
static const int OUTPUT_RECORD_SIZE = 16384; // Must be power of 2
36
wrap_bi (int buffer_index) // wrap buffer index
38
return buffer_index & (OUTPUT_RECORD_SIZE - 1);
42
incr_bi (int buffer_index) // increment buffer index
44
return wrap_bi (buffer_index + 1);
48
decr_bi (int buffer_index) // decrement buffer index
50
return wrap_bi (buffer_index - 1);
53
gr_oscope_guts::gr_oscope_guts (double sample_rate, gr_msg_queue_sptr 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),
64
d_decimator_count (0),
65
d_decimator_count_init (1),
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)
72
for (int i = 0; i < MAX_CHANNELS; i++)
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++)
81
// be sure buffer is full before first write
83
update_rate_or_decimation_changed ();
86
gr_oscope_guts::~gr_oscope_guts ()
88
for (int i = 0; i < MAX_CHANNELS; i++)
89
delete [] d_buffer[i];
94
// \p channel_data points to nchannels float values. These are the values
95
// for each channel at this sample time.
98
gr_oscope_guts::process_sample (const float *channel_data)
101
if (d_decimator_count > 0)
104
d_decimator_count = d_decimator_count_init;
106
if (d_trigger_mode != gr_TRIG_MODE_STRIPCHART)
108
for (int i = 0; i < d_nchannels; i++)
109
d_buffer[i][d_obi] = channel_data[i]; // copy data into buffer
114
if (d_hold_off_count <= 0)
115
enter_look_for_trigger ();
118
case LOOK_FOR_TRIGGER:
119
if (found_trigger ())
120
enter_post_trigger ();
124
d_post_trigger_count--;
125
if (d_post_trigger_count <= 0){
126
write_output_records ();
135
d_obi = incr_bi (d_obi);
139
for (int i = 0; i < d_nchannels; i++)
141
for (int j = OUTPUT_RECORD_SIZE-1; j > 0; j--)
143
d_buffer[i][j] = d_buffer[i][j-1];
145
d_buffer[i][0] = channel_data[i];
147
write_output_records();
152
* Functions called on state entry
156
gr_oscope_guts::enter_hold_off ()
159
d_hold_off_count = d_hold_off_count_init;
163
gr_oscope_guts::enter_look_for_trigger ()
165
d_pre_trigger_count = 0;
166
d_state = LOOK_FOR_TRIGGER;
170
gr_oscope_guts::enter_post_trigger ()
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--;
179
// ----------------------------------------------------------------
180
// returns true if trigger found
183
gr_oscope_guts::found_trigger ()
185
float prev_sample = d_buffer[d_trigger_channel][decr_bi(d_obi)];
186
float new_sample = d_buffer[d_trigger_channel][d_obi];
188
switch (d_trigger_mode){
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;
194
case gr_TRIG_MODE_NORM: //look for trigger
195
switch (d_trigger_slope){
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;
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;
206
//calculate the trigger offset in % sample
207
d_trigger_off = (d_trigger_level - prev_sample)/(new_sample - prev_sample);
210
case gr_TRIG_MODE_FREE: //free run mode, always trigger
220
// ----------------------------------------------------------------
221
// write output records (duh!)
224
gr_oscope_guts::write_output_records ()
226
// if the output queue if full, drop the data like its hot.
227
if (d_msgq->full_p())
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
236
float *out = (float *)msg->msg(); // get pointer to raw message buffer
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)];
243
out += OUTPUT_RECORD_SIZE;
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
252
// ----------------------------------------------------------------
255
gr_oscope_guts::set_update_rate (double update_rate)
257
d_update_rate = std::min (std::max (1./10., update_rate), d_sample_rate);
258
update_rate_or_decimation_changed ();
263
gr_oscope_guts::set_decimation_count (int decimator_count)
265
decimator_count = std::max (1, decimator_count);
266
d_decimator_count_init = decimator_count;
267
update_rate_or_decimation_changed ();
272
gr_oscope_guts::set_sample_rate(double sample_rate)
274
d_sample_rate = sample_rate;
275
return set_update_rate(update_rate());
280
gr_oscope_guts::update_rate_or_decimation_changed ()
282
d_hold_off_count_init =
283
(int) rint (d_sample_rate / d_update_rate / d_decimator_count_init);
287
gr_oscope_guts::set_trigger_channel (int channel)
289
if (channel >= 0 && channel < d_nchannels){
290
d_trigger_channel = channel;
299
gr_oscope_guts::set_trigger_mode (gr_trigger_mode mode)
301
d_trigger_mode = mode;
307
gr_oscope_guts::set_trigger_slope (gr_trigger_slope slope)
309
d_trigger_slope = slope;
315
gr_oscope_guts::set_trigger_level (double trigger_level)
317
d_trigger_level = trigger_level;
323
gr_oscope_guts::set_trigger_level_auto ()
325
// find the level 1/2 way between the min and the max
327
float min_v = d_buffer[d_trigger_channel][0];
328
float max_v = d_buffer[d_trigger_channel][0];
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]);
334
return set_trigger_level((min_v + max_v) * 0.5);
338
gr_oscope_guts::set_num_channels(int nchannels)
340
if (nchannels > 0 && nchannels <= MAX_CHANNELS){
341
d_nchannels = nchannels;
349
gr_oscope_guts::trigger_changed ()
351
enter_look_for_trigger ();
357
gr_oscope_guts::num_channels () const
363
gr_oscope_guts::sample_rate () const
365
return d_sample_rate;
369
gr_oscope_guts::update_rate () const
371
return d_update_rate;
375
gr_oscope_guts::get_decimation_count () const
377
return d_decimator_count_init;
381
gr_oscope_guts::get_trigger_channel () const
383
return d_trigger_channel;
387
gr_oscope_guts::get_trigger_mode () const
389
return d_trigger_mode;
393
gr_oscope_guts::get_trigger_slope () const
395
return d_trigger_slope;
399
gr_oscope_guts::get_trigger_level () const
401
return d_trigger_level;
405
gr_oscope_guts::get_samples_per_output_record () const
407
return OUTPUT_RECORD_SIZE;