custom wx event to post data, avoid threading issues
[debian/gnuradio] / gr-wxgui / src / python / const_window.py
1 #
2 # Copyright 2008 Free Software Foundation, Inc.
3 #
4 # This file is part of GNU Radio
5 #
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)
9 # any later version.
10 #
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.
15 #
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.
20 #
21
22 ##################################################
23 # Imports
24 ##################################################
25 import plotter
26 import common
27 import wx
28 import numpy
29 import math
30 import pubsub
31 from constants import *
32 from gnuradio import gr #for gr.prefs
33
34 ##################################################
35 # Constants
36 ##################################################
37 SLIDER_STEPS = 200
38 ALPHA_MIN_EXP, ALPHA_MAX_EXP = -6, -0.301
39 GAIN_MU_MIN_EXP, GAIN_MU_MAX_EXP = -6, -0.301
40 DEFAULT_FRAME_RATE = gr.prefs().get_long('wxgui', 'const_rate', 5)
41 DEFAULT_WIN_SIZE = (500, 400)
42 DEFAULT_CONST_SIZE = gr.prefs().get_long('wxgui', 'const_size', 2048)
43 CONST_PLOT_COLOR_SPEC = (0, 0, 1)
44 MARKER_TYPES = (
45         ('Dot Small', 1.0),
46         ('Dot Medium', 2.0),
47         ('Dot Large', 3.0),
48         ('Line Link', None),
49 )
50 DEFAULT_MARKER_TYPE = 2.0
51
52 ##################################################
53 # Constellation window control panel
54 ##################################################
55 class control_panel(wx.Panel):
56         """
57         A control panel with wx widgits to control the plotter.
58         """
59         def __init__(self, parent):
60                 """
61                 Create a new control panel.
62                 @param parent the wx parent window
63                 """
64                 self.parent = parent
65                 wx.Panel.__init__(self, parent, -1, style=wx.SUNKEN_BORDER)
66                 control_box = wx.BoxSizer(wx.VERTICAL)
67                 self.marker_index = 2
68                 #begin control box
69                 control_box.AddStretchSpacer()
70                 control_box.Add(common.LabelText(self, 'Options'), 0, wx.ALIGN_CENTER)
71                 #marker
72                 control_box.AddStretchSpacer()
73                 self.marker_chooser = common.DropDownController(self, 'Marker', MARKER_TYPES, parent, MARKER_KEY)
74                 control_box.Add(self.marker_chooser, 0, wx.EXPAND)
75                 #alpha
76                 control_box.AddStretchSpacer()
77                 self.alpha_slider = common.LogSliderController(
78                         self, 'Alpha',
79                         ALPHA_MIN_EXP, ALPHA_MAX_EXP, SLIDER_STEPS,
80                         parent.ext_controller, parent.alpha_key,
81                 )
82                 control_box.Add(self.alpha_slider, 0, wx.EXPAND)
83                 #gain_mu
84                 control_box.AddStretchSpacer()
85                 self.gain_mu_slider = common.LogSliderController(
86                         self, 'Gain Mu',
87                         GAIN_MU_MIN_EXP, GAIN_MU_MAX_EXP, SLIDER_STEPS,
88                         parent.ext_controller, parent.gain_mu_key,
89                 )
90                 control_box.Add(self.gain_mu_slider, 0, wx.EXPAND)
91                 #run/stop
92                 control_box.AddStretchSpacer()
93                 self.run_button = common.ToggleButtonController(self, parent, RUNNING_KEY, 'Stop', 'Run')
94                 control_box.Add(self.run_button, 0, wx.EXPAND)
95                 #set sizer
96                 self.SetSizerAndFit(control_box)
97
98 ##################################################
99 # Constellation window with plotter and control panel
100 ##################################################
101 class const_window(wx.Panel, pubsub.pubsub, common.prop_setter):
102         def __init__(
103                 self,
104                 parent,
105                 controller,
106                 size,
107                 title,
108                 msg_key,
109                 alpha_key,
110                 beta_key,
111                 gain_mu_key,
112                 gain_omega_key,
113         ):
114                 pubsub.pubsub.__init__(self)
115                 #setup
116                 self.ext_controller = controller
117                 self.alpha_key = alpha_key
118                 self.beta_key = beta_key
119                 self.gain_mu_key = gain_mu_key
120                 self.gain_omega_key = gain_omega_key
121                 #init panel and plot
122                 wx.Panel.__init__(self, parent, -1, style=wx.SIMPLE_BORDER)
123                 self.plotter = plotter.channel_plotter(self)
124                 self.plotter.SetSize(wx.Size(*size))
125                 self.plotter.set_title(title)
126                 self.plotter.set_x_label('Inphase')
127                 self.plotter.set_y_label('Quadrature')
128                 self.plotter.enable_point_label(True)
129                 #setup the box with plot and controls
130                 self.control_panel = control_panel(self)
131                 main_box = wx.BoxSizer(wx.HORIZONTAL)
132                 main_box.Add(self.plotter, 1, wx.EXPAND)
133                 main_box.Add(self.control_panel, 0, wx.EXPAND)
134                 self.SetSizerAndFit(main_box)
135                 #alpha and gain mu 2nd orders
136                 def set_beta(alpha): self.ext_controller[self.beta_key] = .25*alpha**2
137                 self.ext_controller.subscribe(self.alpha_key, set_beta)
138                 def set_gain_omega(gain_mu): self.ext_controller[self.gain_omega_key] = .25*gain_mu**2
139                 self.ext_controller.subscribe(self.gain_mu_key, set_gain_omega)
140                 #initial setup
141                 self.ext_controller[self.alpha_key] = self.ext_controller[self.alpha_key]
142                 self.ext_controller[self.gain_mu_key] = self.ext_controller[self.gain_mu_key]
143                 self._register_set_prop(self, RUNNING_KEY, True)
144                 self._register_set_prop(self, X_DIVS_KEY, 8)
145                 self._register_set_prop(self, Y_DIVS_KEY, 8)
146                 self._register_set_prop(self, MARKER_KEY, DEFAULT_MARKER_TYPE)
147                 #register events
148                 self.ext_controller.subscribe(msg_key, self.handle_msg)
149                 for key in (
150                         X_DIVS_KEY, Y_DIVS_KEY,
151                 ): self.subscribe(key, self.update_grid)
152                 #initial update
153                 self.update_grid()
154
155         def handle_msg(self, msg):
156                 """
157                 Plot the samples onto the complex grid.
158                 @param msg the array of complex samples
159                 """
160                 if not self[RUNNING_KEY]: return
161                 #convert to complex floating point numbers
162                 samples = numpy.fromstring(msg, numpy.complex64)
163                 real = numpy.real(samples)
164                 imag = numpy.imag(samples)
165                 #plot
166                 self.plotter.set_waveform(
167                         channel=0,
168                         samples=(real, imag),
169                         color_spec=CONST_PLOT_COLOR_SPEC,
170                         marker=self[MARKER_KEY],
171                 )
172                 #update the plotter
173                 self.plotter.update()
174
175         def update_grid(self):
176                 #grid parameters
177                 x_divs = self[X_DIVS_KEY]
178                 y_divs = self[Y_DIVS_KEY]
179                 #update the x axis
180                 x_max = 2.0
181                 self.plotter.set_x_grid(-x_max, x_max, common.get_clean_num(2.0*x_max/x_divs))
182                 #update the y axis
183                 y_max = 2.0
184                 self.plotter.set_y_grid(-y_max, y_max, common.get_clean_num(2.0*y_max/y_divs))
185                 #update plotter
186                 self.plotter.update()
187
188
189
190