2 # Copyright 2008 Free Software Foundation, Inc.
4 # This file is part of GNU Radio
6 # GNU Radio is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3, or (at your option)
11 # GNU Radio is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with GNU Radio; see the file COPYING. If not, write to
18 # the Free Software Foundation, Inc., 51 Franklin Street,
19 # Boston, MA 02110-1301, USA.
22 ##################################################
24 ##################################################
29 from constants import *
30 from gnuradio import gr #for gr.prefs
32 ##################################################
34 ##################################################
35 NEG_INF = float('-inf')
37 AVG_ALPHA_MIN_EXP, AVG_ALPHA_MAX_EXP = -3, 0
38 DEFAULT_NUMBER_RATE = gr.prefs().get_long('wxgui', 'number_rate', 5)
39 DEFAULT_WIN_SIZE = (300, 300)
40 DEFAULT_GAUGE_RANGE = 1000
42 ##################################################
43 # Number window control panel
44 ##################################################
45 class control_panel(wx.Panel):
47 A control panel with wx widgits to control the averaging.
50 def __init__(self, parent):
52 Create a new control panel.
53 @param parent the wx parent window
56 wx.Panel.__init__(self, parent, -1, style=wx.SUNKEN_BORDER)
57 control_box = wx.BoxSizer(wx.VERTICAL)
58 #checkboxes for average and peak hold
59 control_box.AddStretchSpacer()
60 control_box.Add(common.LabelText(self, 'Options'), 0, wx.ALIGN_CENTER)
61 self.average_check_box = common.CheckBoxController(self, 'Average', parent.ext_controller, parent.average_key)
62 control_box.Add(self.average_check_box, 0, wx.EXPAND)
63 self.peak_hold_check_box = common.CheckBoxController(self, 'Peak Hold', parent, PEAK_HOLD_KEY)
64 control_box.Add(self.peak_hold_check_box, 0, wx.EXPAND)
65 control_box.AddSpacer(2)
66 self.avg_alpha_slider = common.LogSliderController(
68 AVG_ALPHA_MIN_EXP, AVG_ALPHA_MAX_EXP, SLIDER_STEPS,
69 parent.ext_controller, parent.avg_alpha_key,
70 formatter=lambda x: ': %.4f'%x,
72 parent.ext_controller.subscribe(parent.average_key, self.avg_alpha_slider.Enable)
73 control_box.Add(self.avg_alpha_slider, 0, wx.EXPAND)
75 control_box.AddStretchSpacer()
76 self.run_button = common.ToggleButtonController(self, parent, RUNNING_KEY, 'Stop', 'Run')
77 control_box.Add(self.run_button, 0, wx.EXPAND)
79 self.SetSizerAndFit(control_box)
81 ##################################################
82 # Numbersink window with label and gauges
83 ##################################################
84 class number_window(wx.Panel, pubsub.pubsub, common.prop_setter):
102 pubsub.pubsub.__init__(self)
103 wx.Panel.__init__(self, parent, -1, style=wx.SUNKEN_BORDER)
105 self.peak_val_real = NEG_INF
106 self.peak_val_imag = NEG_INF
107 self.ext_controller = controller
112 self.decimal_places = decimal_places
113 self.average_key = average_key
114 self.avg_alpha_key = avg_alpha_key
115 #setup the box with display and controls
116 self.control_panel = control_panel(self)
117 main_box = wx.BoxSizer(wx.HORIZONTAL)
118 sizer = wx.BoxSizer(wx.VERTICAL)
119 main_box.Add(sizer, 1, wx.EXPAND)
120 main_box.Add(self.control_panel, 0, wx.EXPAND)
121 sizer.Add(common.LabelText(self, title), 1, wx.ALIGN_CENTER)
122 self.text = wx.StaticText(self, size=(size[0], -1))
123 sizer.Add(self.text, 1, wx.EXPAND)
124 self.gauge_real = wx.Gauge(self, range=DEFAULT_GAUGE_RANGE, style=wx.GA_HORIZONTAL)
125 self.gauge_imag = wx.Gauge(self, range=DEFAULT_GAUGE_RANGE, style=wx.GA_HORIZONTAL)
127 self.show_gauges(show_gauge)
128 sizer.Add(self.gauge_real, 1, wx.EXPAND)
129 sizer.Add(self.gauge_imag, 1, wx.EXPAND)
130 self.SetSizerAndFit(main_box)
132 self.ext_controller[self.average_key] = self.ext_controller[self.average_key]
133 self.ext_controller[self.avg_alpha_key] = self.ext_controller[self.avg_alpha_key]
134 self._register_set_prop(self, PEAK_HOLD_KEY, peak_hold)
135 self._register_set_prop(self, RUNNING_KEY, True)
137 self.ext_controller.subscribe(msg_key, self.handle_msg)
139 def show_gauges(self, show_gauge):
141 Show or hide the gauges.
142 If this is real, never show the imaginary gauge.
143 @param show_gauge true to show
145 if show_gauge: self.gauge_real.Show()
146 else: self.gauge_real.Hide()
147 if show_gauge and not self.real: self.gauge_imag.Show()
148 else: self.gauge_imag.Hide()
150 def handle_msg(self, msg):
152 Handle a message from the message queue.
153 Convert the string based message into a float or complex.
154 If more than one number was read, only take the last number.
155 Perform peak hold operations, set the gauges and display.
156 @param msg the number sample as a character array
158 if not self[RUNNING_KEY]: return
160 def set_gauge_value(gauge, value):
161 gauge_val = DEFAULT_GAUGE_RANGE*(value-self.minval)/(self.maxval-self.minval)
162 gauge_val = max(0, gauge_val) #clip
163 gauge_val = min(DEFAULT_GAUGE_RANGE, gauge_val) #clip
164 gauge.SetValue(gauge_val)
165 format_string = "%%.%df"%self.decimal_places
167 sample = numpy.fromstring(msg, numpy.float32)[-1]
168 if self[PEAK_HOLD_KEY]: sample = self.peak_val_real = max(self.peak_val_real, sample)
169 label_text = "%s %s"%(format_string%sample, self.units)
170 set_gauge_value(self.gauge_real, sample)
172 sample = numpy.fromstring(msg, numpy.complex64)[-1]
173 if self[PEAK_HOLD_KEY]:
174 self.peak_val_real = max(self.peak_val_real, sample.real)
175 self.peak_val_imag = max(self.peak_val_imag, sample.imag)
176 sample = self.peak_val_real + self.peak_val_imag*1j
177 label_text = "%s + %sj %s"%(format_string%sample.real, format_string%sample.imag, self.units)
178 set_gauge_value(self.gauge_real, sample.real)
179 set_gauge_value(self.gauge_imag, sample.imag)
181 self.text.SetLabel(label_text)
183 if not self[PEAK_HOLD_KEY]:
184 self.peak_val_real = NEG_INF
185 self.peak_val_imag = NEG_INF