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 = 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 (double sample_rate, gr_msg_queue_sptr msgq)
57 d_trigger_mode (gr_TRIG_MODE_AUTO),
58 d_trigger_slope (gr_TRIG_SLOPE_POS),
59 d_trigger_channel (0),
60 d_sample_rate (sample_rate),
65 d_decimator_count (0),
66 d_decimator_count_init (1),
68 d_hold_off_count_init (OUTPUT_RECORD_SIZE/2-1),
69 d_pre_trigger_count (0),
70 d_post_trigger_count (0),
71 d_post_trigger_count_init (OUTPUT_RECORD_SIZE/2)
73 for (int i = 0; i < MAX_CHANNELS; i++)
76 for (int i = 0; i < MAX_CHANNELS; i++){
77 d_buffer[i] = new float [OUTPUT_RECORD_SIZE];
78 for (int j = 0; j < OUTPUT_RECORD_SIZE; j++)
82 // be sure buffer is full before first write
84 update_rate_or_decimation_changed ();
87 gr_oscope_guts::~gr_oscope_guts ()
89 for (int i = 0; i < MAX_CHANNELS; i++)
90 delete [] d_buffer[i];
95 // \p channel_data points to nchannels float values. These are the values
96 // for each channel at this sample time.
99 gr_oscope_guts::process_sample (const float *channel_data)
102 if (d_decimator_count > 0)
105 d_decimator_count = d_decimator_count_init;
107 if (d_trigger_mode != gr_TRIG_MODE_STRIPCHART)
109 for (int i = 0; i < d_nchannels; i++)
110 d_buffer[i][d_obi] = channel_data[i]; // copy data into buffer
115 if (d_hold_off_count <= 0)
116 enter_look_for_trigger ();
119 case LOOK_FOR_TRIGGER:
120 if (found_trigger ())
121 enter_post_trigger ();
125 d_post_trigger_count--;
126 if (d_post_trigger_count <= 0){
127 write_output_records ();
136 d_obi = incr_bi (d_obi);
140 for (int i = 0; i < d_nchannels; i++)
142 for (int j = OUTPUT_RECORD_SIZE-1; j >= 0; j--)
144 d_buffer[i][j] = d_buffer[i][j-1];
146 d_buffer[i][0] = channel_data[i];
148 write_output_records();
153 * Functions called on state entry
157 gr_oscope_guts::enter_hold_off ()
160 d_hold_off_count = d_hold_off_count_init;
164 gr_oscope_guts::enter_look_for_trigger ()
166 d_pre_trigger_count = 0;
167 d_state = LOOK_FOR_TRIGGER;
171 gr_oscope_guts::enter_post_trigger ()
173 d_state = POST_TRIGGER;
174 d_post_trigger_count = d_post_trigger_count_init;
175 //ensure that the trigger offset is no more than than half a sample
176 if (d_trigger_off > .5) d_trigger_off -= 1;
177 else d_post_trigger_count--;
180 // ----------------------------------------------------------------
181 // returns true if trigger found
184 gr_oscope_guts::found_trigger ()
186 float prev_sample = d_buffer[d_trigger_channel][decr_bi(d_obi)];
187 float new_sample = d_buffer[d_trigger_channel][d_obi];
189 switch (d_trigger_mode){
191 case gr_TRIG_MODE_AUTO: //too many samples without a trigger
192 d_pre_trigger_count++;
193 if (d_pre_trigger_count > OUTPUT_RECORD_SIZE/2) return true;
195 case gr_TRIG_MODE_NORM: //look for trigger
196 switch (d_trigger_slope){
198 case gr_TRIG_SLOPE_POS: //trigger point in pos slope?
199 if (new_sample < d_trigger_level || prev_sample >= d_trigger_level) return false;
202 case gr_TRIG_SLOPE_NEG: //trigger point in neg slope?
203 if (new_sample > d_trigger_level || prev_sample <= d_trigger_level) return false;
207 //calculate the trigger offset in % sample
208 d_trigger_off = (d_trigger_level - prev_sample)/(new_sample - prev_sample);
211 case gr_TRIG_MODE_FREE: //free run mode, always trigger
221 // ----------------------------------------------------------------
222 // write output records (duh!)
225 gr_oscope_guts::write_output_records ()
227 // if the output queue if full, drop the data like its hot.
228 if (d_msgq->full_p())
230 // Build a message to hold the output records
231 gr_message_sptr msg =
232 gr_make_message(0, // msg type
233 d_nchannels, // arg1 for other side
234 OUTPUT_RECORD_SIZE, // arg2 for other side
235 ((d_nchannels * OUTPUT_RECORD_SIZE) + 1) * sizeof(float)); // sizeof payload
237 float *out = (float *)msg->msg(); // get pointer to raw message buffer
239 for (int ch = 0; ch < d_nchannels; ch++){
240 // note that d_obi + 1 points at the oldest sample in the buffer
241 for (int i = 0; i < OUTPUT_RECORD_SIZE; i++){
242 out[i] = d_buffer[ch][wrap_bi(d_obi + 1 + i)];
244 out += OUTPUT_RECORD_SIZE;
246 //Set the last sample as the trigger offset:
247 // The non gl scope sink will not look at this last sample.
248 // The gl scope sink will use this last sample as an offset.
249 out[0] = d_trigger_off;
250 d_msgq->handle(msg); // send the msg
253 // ----------------------------------------------------------------
256 gr_oscope_guts::set_update_rate (double update_rate)
258 d_update_rate = std::min (std::max (1./10., update_rate), d_sample_rate);
259 update_rate_or_decimation_changed ();
264 gr_oscope_guts::set_decimation_count (int decimator_count)
266 decimator_count = std::max (1, decimator_count);
267 d_decimator_count_init = decimator_count;
268 update_rate_or_decimation_changed ();
273 gr_oscope_guts::set_sample_rate(double sample_rate)
275 d_sample_rate = sample_rate;
276 return set_update_rate(update_rate());
281 gr_oscope_guts::update_rate_or_decimation_changed ()
283 d_hold_off_count_init =
284 (int) rint (d_sample_rate / d_update_rate / d_decimator_count_init);
288 gr_oscope_guts::set_trigger_channel (int channel)
290 if (channel >= 0 && channel < d_nchannels){
291 d_trigger_channel = channel;
300 gr_oscope_guts::set_trigger_mode (gr_trigger_mode mode)
302 d_trigger_mode = mode;
308 gr_oscope_guts::set_trigger_slope (gr_trigger_slope slope)
310 d_trigger_slope = slope;
316 gr_oscope_guts::set_trigger_level (double trigger_level)
318 d_trigger_level = trigger_level;
324 gr_oscope_guts::set_trigger_level_auto ()
326 // find the level 1/2 way between the min and the max
328 float min_v = d_buffer[d_trigger_channel][0];
329 float max_v = d_buffer[d_trigger_channel][0];
331 for (int i = 1; i < OUTPUT_RECORD_SIZE; i++){
332 min_v = std::min (min_v, d_buffer[d_trigger_channel][i]);
333 max_v = std::max (max_v, d_buffer[d_trigger_channel][i]);
335 return set_trigger_level((min_v + max_v) * 0.5);
339 gr_oscope_guts::set_num_channels(int nchannels)
341 if (nchannels > 0 && nchannels <= MAX_CHANNELS){
342 d_nchannels = nchannels;
350 gr_oscope_guts::trigger_changed ()
352 enter_look_for_trigger ();
358 gr_oscope_guts::num_channels () const
364 gr_oscope_guts::sample_rate () const
366 return d_sample_rate;
370 gr_oscope_guts::update_rate () const
372 return d_update_rate;
376 gr_oscope_guts::get_decimation_count () const
378 return d_decimator_count_init;
382 gr_oscope_guts::get_trigger_channel () const
384 return d_trigger_channel;
388 gr_oscope_guts::get_trigger_mode () const
390 return d_trigger_mode;
394 gr_oscope_guts::get_trigger_slope () const
396 return d_trigger_slope;
400 gr_oscope_guts::get_trigger_level () const
402 return d_trigger_level;
406 gr_oscope_guts::get_samples_per_output_record () const
408 return OUTPUT_RECORD_SIZE;