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 2, 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 = 2048; // must be power of 2
37 wrap_bi (int buffer_index) // wrap buffer index
39 return buffer_index & (OUTPUT_RECORD_SIZE - 1);
43 incr_bi (int buffer_index) // increment buffer index
45 return wrap_bi (buffer_index + 1);
49 decr_bi (int buffer_index) // decrement buffer index
51 return wrap_bi (buffer_index - 1);
54 gr_oscope_guts::gr_oscope_guts (int nchannels, double sample_rate, gr_msg_queue_sptr msgq)
55 : d_nchannels (nchannels),
57 d_trigger_mode (gr_TRIG_AUTO),
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_post_trigger_count (0),
69 d_post_trigger_count_init (OUTPUT_RECORD_SIZE/2),
72 if (d_nchannels > MAX_CHANNELS){
73 fprintf (stderr, "gr_oscope_guts: too many channels. MAX_CHANNELS = %d\n", MAX_CHANNELS);
74 throw std::runtime_error ("too many channels");
77 for (int i = 0; i < MAX_CHANNELS; i++)
80 for (int i = 0; i < d_nchannels; i++){
81 d_buffer[i] = new float [OUTPUT_RECORD_SIZE];
82 for (int j = 0; j < OUTPUT_RECORD_SIZE; j++)
86 // be sure buffer is full before first write
88 update_rate_or_decimation_changed ();
91 gr_oscope_guts::~gr_oscope_guts ()
93 for (int i = 0; i < MAX_CHANNELS; i++)
94 delete [] d_buffer[i];
99 // \p channel_data points to nchannels float values. These are the values
100 // for each channel at this sample time.
103 gr_oscope_guts::process_sample (const float *channel_data)
106 if (d_decimator_count > 0)
109 d_decimator_count = d_decimator_count_init;
111 for (int i = 0; i < d_nchannels; i++)
112 d_buffer[i][d_obi] = channel_data[i]; // copy data into buffer
119 if (d_hold_off_count <= 0)
120 enter_look_for_trigger ();
123 case LOOK_FOR_TRIGGER:
124 trigger = found_trigger (d_buffer[d_trigger_channel][d_obi]);
126 enter_post_trigger ();
127 if (trigger < 0) // previous sample was closer
128 d_post_trigger_count--;
133 d_post_trigger_count--;
134 if (d_post_trigger_count <= 0){
135 write_output_records ();
144 d_obi = incr_bi (d_obi);
148 * Functions called on state entry
152 gr_oscope_guts::enter_hold_off ()
155 d_hold_off_count = d_hold_off_count_init;
159 gr_oscope_guts::enter_look_for_trigger ()
161 d_state = LOOK_FOR_TRIGGER;
162 d_prev_sample = d_buffer[d_trigger_channel][d_obi];
166 gr_oscope_guts::enter_post_trigger ()
168 d_state = POST_TRIGGER;
169 d_post_trigger_count = d_post_trigger_count_init;
172 // ----------------------------------------------------------------
173 // returns 0 if no trigger found.
174 // returns +1 if this sample is the trigger point
175 // returns -1 if the previous sample is the trigger point
178 gr_oscope_guts::found_trigger (float new_sample)
180 float prev_sample = d_prev_sample;
181 d_prev_sample = new_sample;
184 switch (d_trigger_mode){
186 case gr_TRIG_AUTO: // always trigger
189 case gr_TRIG_POS_SLOPE:
190 trig = prev_sample < d_trigger_level && new_sample >= d_trigger_level;
192 if (fabs (prev_sample - d_trigger_level) < fabs (new_sample - d_trigger_level))
199 case gr_TRIG_NEG_SLOPE:
200 trig = prev_sample > d_trigger_level && new_sample <= d_trigger_level;
202 if (fabs (prev_sample - d_trigger_level) < fabs (new_sample - d_trigger_level))
215 // ----------------------------------------------------------------
216 // write output records (duh!)
219 gr_oscope_guts::write_output_records ()
221 // if the output queue if full, drop the data on the ground.
222 if (d_msgq->full_p())
225 // Build a message to hold the output records
226 gr_message_sptr msg =
227 gr_make_message(0, // msg type
228 d_nchannels, // arg1 for other side
229 OUTPUT_RECORD_SIZE, // arg2 for other side
230 d_nchannels * OUTPUT_RECORD_SIZE * sizeof(float)); // sizeof payload
232 float *out = (float *)msg->msg(); // get pointer to raw message buffer
234 for (int ch = 0; ch < d_nchannels; ch++){
235 // note that d_obi + 1 points at the oldest sample in the buffer
236 for (int i = 0; i < OUTPUT_RECORD_SIZE; i++)
237 out[i] = d_buffer[ch][wrap_bi(d_obi + 1 + i)];
239 out += OUTPUT_RECORD_SIZE;
242 d_msgq->handle(msg); // send the msg
245 // ----------------------------------------------------------------
248 gr_oscope_guts::set_update_rate (double update_rate)
250 d_update_rate = std::min (std::max (1./10., update_rate), d_sample_rate);
251 update_rate_or_decimation_changed ();
256 gr_oscope_guts::set_decimation_count (int decimator_count)
258 decimator_count = std::max (1, decimator_count);
259 d_decimator_count_init = decimator_count;
260 update_rate_or_decimation_changed ();
265 gr_oscope_guts::set_sample_rate(double sample_rate)
267 d_sample_rate = sample_rate;
268 return set_update_rate(update_rate());
273 gr_oscope_guts::update_rate_or_decimation_changed ()
275 d_hold_off_count_init =
276 (int) rint (d_sample_rate / d_update_rate / d_decimator_count_init);
280 gr_oscope_guts::set_trigger_channel (int channel)
282 if (channel >= 0 && channel < d_nchannels){
283 d_trigger_channel = channel;
292 gr_oscope_guts::set_trigger_mode (gr_trigger_mode mode)
295 case gr_TRIG_POS_SLOPE:
296 case gr_TRIG_NEG_SLOPE:
298 d_trigger_mode = mode;
306 gr_oscope_guts::set_trigger_level (double trigger_level)
308 d_trigger_level = trigger_level;
314 gr_oscope_guts::set_trigger_level_auto ()
316 // find the level 1/2 way between the min and the max
318 float min_v = d_buffer[d_trigger_channel][0];
319 float max_v = d_buffer[d_trigger_channel][0];
321 for (int i = 1; i < OUTPUT_RECORD_SIZE; i++){
322 min_v = std::min (min_v, d_buffer[d_trigger_channel][i]);
323 max_v = std::max (max_v, d_buffer[d_trigger_channel][i]);
326 d_trigger_level = (min_v + max_v) * 0.5;
332 gr_oscope_guts::trigger_changed ()
334 // d_prev_sample = d_buffer[d_trigger_channel][decr_bi(d_obi)];
335 enter_look_for_trigger ();
341 gr_oscope_guts::num_channels () const
347 gr_oscope_guts::sample_rate () const
349 return d_sample_rate;
353 gr_oscope_guts::update_rate () const
355 return d_update_rate;
359 gr_oscope_guts::get_decimation_count () const
361 return d_decimator_count_init;
365 gr_oscope_guts::get_trigger_channel () const
367 return d_trigger_channel;
371 gr_oscope_guts::get_trigger_mode () const
373 return d_trigger_mode;
377 gr_oscope_guts::get_trigger_level () const
379 return d_trigger_level;
383 gr_oscope_guts::get_samples_per_output_record () const
385 return OUTPUT_RECORD_SIZE;