summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormax <max@65a5c917-d112-43f1-993d-58c26a4786be>2011-07-18 13:34:45 +0000
committermax <max@65a5c917-d112-43f1-993d-58c26a4786be>2011-07-18 13:34:45 +0000
commit7d86e01d42ed652b4d1fd315cb5bfc6d6e6b7e8e (patch)
treee8ebe201b17dd9c46a1c814f503cc7780e300896
parentad335ff1e62abeee6454cd6d8b55908483155854 (diff)
add fac,constellation,gl/nongl
git-svn-id: http://op25.osmocom.org/svn/trunk@291 65a5c917-d112-43f1-993d-58c26a4786be
-rw-r--r--repeater/src/lib/Makefile.am1
-rw-r--r--repeater/src/lib/repeater.i12
-rw-r--r--repeater/src/lib/repeater_p25_frame_assembler.cc30
-rw-r--r--repeater/src/lib/repeater_s2v.cc101
-rw-r--r--repeater/src/lib/repeater_s2v.h81
-rw-r--r--repeater/src/lib/rs.cc8
-rwxr-xr-xrepeater/src/python/scope.py614
7 files changed, 781 insertions, 66 deletions
diff --git a/repeater/src/lib/Makefile.am b/repeater/src/lib/Makefile.am
index 73dfd1b..20d95a5 100644
--- a/repeater/src/lib/Makefile.am
+++ b/repeater/src/lib/Makefile.am
@@ -61,6 +61,7 @@ ourlib_LTLIBRARIES = _repeater.la
_repeater_la_SOURCES = repeater\
repeater.cc \
repeater_fsk4_slicer_fb.cc \
+ repeater_s2v.cc \
repeater_p25_frame_assembler.cc \
repeater_pipe.cc \
repeater_ctcss_squelch_ff.cc \
diff --git a/repeater/src/lib/repeater.i b/repeater/src/lib/repeater.i
index a171c3a..3edb02c 100644
--- a/repeater/src/lib/repeater.i
+++ b/repeater/src/lib/repeater.i
@@ -9,6 +9,7 @@
#include "gnuradio_swig_bug_workaround.h" // mandatory bug fix
#include "repeater_squelch_base_ff.h"
#include "repeater_fsk4_slicer_fb.h"
+#include "repeater_s2v.h"
#include "repeater_p25_frame_assembler.h"
#include "repeater_pipe.h"
#include "repeater_ctcss_squelch_ff.h"
@@ -155,3 +156,14 @@ private:
public:
void unkey(void);
};
+
+GR_SWIG_BLOCK_MAGIC(repeater,s2v);
+
+repeater_s2v_sptr repeater_make_s2v (size_t item_size, size_t nitems_per_block);
+
+class repeater_s2v : public gr_block
+{
+private:
+ repeater_s2v (size_t item_size, size_t nitems_per_block);
+};
+
diff --git a/repeater/src/lib/repeater_p25_frame_assembler.cc b/repeater/src/lib/repeater_p25_frame_assembler.cc
index 0e5b1c0..6f11326 100644
--- a/repeater/src/lib/repeater_p25_frame_assembler.cc
+++ b/repeater/src/lib/repeater_p25_frame_assembler.cc
@@ -114,26 +114,20 @@ repeater_p25_frame_assembler::general_work (int noutput_items,
for (int i = 0; i < noutput_items; i++){
if(framer->rx_sym(in[i])) { // complete frame was detected
- if (d_debug > 0 && framer->duid == 0x00) {
- ProcHDU(framer->frame_body);
+ if (d_debug >= 10) {
+ fprintf (stderr, "NAC 0x%X DUID 0x%X len %ld errs %d ", framer->nac, framer->duid, framer->frame_size >> 1, framer->bch_errors);
}
- if (d_debug > 10) {
- fprintf (stderr, "NAC 0x%X DUID 0x%X symbols %d BCH errors %d\n", framer->nac, framer->duid, framer->frame_size >> 1, framer->bch_errors);
- switch(framer->duid) {
- case 0x00: // Header DU
- // see above ProcHDU(framer->frame_body);
- break;
- case 0x05: // LDU 1
- ProcLDU1(framer->frame_body);
- break;
- case 0x0a: // LDU 2
- ProcLDU2(framer->frame_body);
- break;
- case 0x0f: // LDU 2
- ProcTDU(framer->frame_body);
- break;
- }
+ if (d_debug >= 10 && framer->duid == 0x00) {
+ ProcHDU(framer->frame_body);
+ } else if (d_debug > 10 && framer->duid == 0x05) {
+ ProcLDU1(framer->frame_body);
+ } else if (d_debug >= 10 && framer->duid == 0x0a) {
+ ProcLDU2(framer->frame_body);
+ } else if (d_debug > 10 && framer->duid == 0x0f) {
+ ProcTDU(framer->frame_body);
}
+ if (d_debug >= 10)
+ fprintf(stderr, "\n");
if (d_do_imbe && (framer->duid == 0x5 || framer->duid == 0xa)) { // if voice - ldu1 or ldu2
for(size_t i = 0; i < nof_voice_codewords; ++i) {
voice_codeword cw(voice_codeword_sz);
diff --git a/repeater/src/lib/repeater_s2v.cc b/repeater/src/lib/repeater_s2v.cc
new file mode 100644
index 0000000..8593116
--- /dev/null
+++ b/repeater/src/lib/repeater_s2v.cc
@@ -0,0 +1,101 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ * Copyright 2010, KA1RBI
+ */
+/*
+ * config.h is generated by configure. It contains the results
+ * of probing for features, options etc. It should be the first
+ * file included in your .cc file.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <repeater_s2v.h>
+#include <gr_io_signature.h>
+#include <stdio.h>
+
+/*
+ * Create a new instance of repeater_s2v and return
+ * a boost shared_ptr. This is effectively the public constructor.
+ */
+repeater_s2v_sptr
+repeater_make_s2v (size_t item_size, size_t nitems_per_block)
+{
+ return repeater_s2v_sptr (new repeater_s2v (item_size, nitems_per_block));
+}
+
+/*
+ * The private constructor
+ */
+repeater_s2v::repeater_s2v (size_t item_size, size_t nitems_per_block)
+ : gr_block ("s2v",
+ gr_make_io_signature (1, 1, item_size),
+ gr_make_io_signature (1, 1, item_size * nitems_per_block)),
+ d_buf_len(0),
+ d_acct (0),
+ d_item_size (item_size),
+ d_nitems_per_block (nitems_per_block)
+{
+}
+
+/*
+ * Our virtual destructor.
+ */
+repeater_s2v::~repeater_s2v ()
+{
+ // nothing else required in this example
+}
+
+static int min(int a, int b) { return ((a<b) ? a : b); }
+
+int
+repeater_s2v::general_work (int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ const float *in = (const float *) input_items[0];
+ unsigned char *out = (unsigned char *) output_items[0];
+ size_t rc=0, amt_left=0, amt_move=0;
+
+ amt_left = DBUFSIZE - d_buf_len;
+ amt_move = min(amt_left, ninput_items[0]);
+ if (amt_move > 0) {
+ memcpy (&d_buf[ d_buf_len * d_item_size ], in, amt_move * d_item_size);
+ d_buf_len += amt_move;
+ }
+
+ if (d_buf_len >= d_nitems_per_block) {
+ memcpy (out, d_buf, d_item_size * d_nitems_per_block);
+ d_buf_len = 0;
+ rc = 1;
+ }
+
+ consume_each(amt_move);
+
+ // fprintf(stderr, "d_acct %ld rc %ld amt_left %ld amt_move %ld d_buf_len %ld\n", d_acct, rc, amt_left, amt_move, d_buf_len);
+
+ // Tell runtime system how many output items we produced.
+ return rc;
+}
diff --git a/repeater/src/lib/repeater_s2v.h b/repeater/src/lib/repeater_s2v.h
new file mode 100644
index 0000000..ce0e707
--- /dev/null
+++ b/repeater/src/lib/repeater_s2v.h
@@ -0,0 +1,81 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef INCLUDED_REPEATER_S2V_H
+#define INCLUDED_REPEATER_S2V_H
+
+#include <gr_block.h>
+
+class repeater_s2v;
+
+/*
+ * We use boost::shared_ptr's instead of raw pointers for all access
+ * to gr_blocks (and many other data structures). The shared_ptr gets
+ * us transparent reference counting, which greatly simplifies storage
+ * management issues. This is especially helpful in our hybrid
+ * C++ / Python system.
+ *
+ * See http://www.boost.org/libs/smart_ptr/smart_ptr.htm
+ *
+ * As a convention, the _sptr suffix indicates a boost::shared_ptr
+ */
+typedef boost::shared_ptr<repeater_s2v> repeater_s2v_sptr;
+
+/*!
+ * \brief Return a shared_ptr to a new instance of repeater_fsk4_slicer_fb.
+ *
+ * To avoid accidental use of raw pointers, repeater_s2v's
+ * constructor is private. repeater_make_s2v is the public
+ * interface for creating new instances.
+ */
+repeater_s2v_sptr repeater_make_s2v (size_t item_size, size_t nitems_per_block);
+
+class repeater_s2v : public gr_block
+{
+private:
+ // The friend declaration allows repeater_make_s2v to
+ // access the private constructor.
+
+ friend repeater_s2v_sptr repeater_make_s2v (size_t item_size, size_t nitems_per_block);
+
+ repeater_s2v (size_t item_size, size_t nitems_per_block);
+
+ static const int DBUFSIZE = 65536;
+
+ char d_buf[ DBUFSIZE * sizeof(gr_complex) ];
+ size_t d_buf_len;
+
+ size_t d_acct;
+ size_t d_item_size;
+ size_t d_nitems_per_block;
+
+ public:
+ ~repeater_s2v (); // public destructor
+
+ // Where all the action really happens
+
+ int general_work (int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+};
+
+#endif /* INCLUDED_REPEATER_S2V_H */
diff --git a/repeater/src/lib/rs.cc b/repeater/src/lib/rs.cc
index 5ae3785..e1dd1d1 100644
--- a/repeater/src/lib/rs.cc
+++ b/repeater/src/lib/rs.cc
@@ -493,7 +493,7 @@ uint32_t ALGID = (HB[40] & 15) * 16 + (HB[41] >> 2);
uint32_t KID = (HB[41] & 3) * 16384 + HB[42] * 256 + HB[43] * 4 + (HB[44] >> 4);
uint32_t TGID = (HB[44] & 15) * 4096 + HB[45] * 64 + HB[46];
-fprintf (stderr, "HDU: rc %d mfid %x alg %x kid %x tgid %d\n", ec, MFID, ALGID, KID, TGID);
+fprintf (stderr, " HDU: rc %d mfid %x alg %x kid %x tgid %d", ec, MFID, ALGID, KID, TGID);
}
@@ -518,7 +518,7 @@ void ProcLC(uint8_t HB[]) {
int pb = HB[39] >> 5;
int sf = (HB[39] & 16) >> 4;
int lco = (HB[39] and 15) * 4 + (HB[40] >> 4);
- fprintf(stderr, "LC: rc %d pb %d sf %d lco %d\n", ec, pb, sf, lco);
+ fprintf(stderr, " LC: rc %d pb %d sf %d lco %d", ec, pb, sf, lco);
}
void ProcLDU1(const_bit_vector A) {
@@ -537,11 +537,11 @@ void ProcLDU2(const_bit_vector A) {
uint32_t ALGID = HB[51] * 4 + (HB[52] >> 4);
uint32_t KID = (HB[52] & 15) * 4096 + HB[53] * 64 + HB[54];
- fprintf(stderr, "LDU2: rc %d ALGID %x KID %x MI ", ec, ALGID, KID);
+ fprintf(stderr, " LDU2: rc %d ALGID %x KID %x MI ", ec, ALGID, KID);
for (int i = 39; i <= 50; i++) {
fprintf(stderr, "%02x ", HB[ i ]);
}
- fprintf(stderr, "\n");
+ // fprintf(stderr, "\n");
}
void ProcTDU(const_bit_vector A) {
diff --git a/repeater/src/python/scope.py b/repeater/src/python/scope.py
index bc6eb24..841d9b3 100755
--- a/repeater/src/python/scope.py
+++ b/repeater/src/python/scope.py
@@ -1,7 +1,12 @@
#!/usr/bin/env python
+# Copyright 2008-2011 Steve Glass
+#
# Copyright 2011 KA1RBI
#
+# Copyright 2003,2004,2005,2006 Free Software Foundation, Inc.
+# (from radiorausch)
+#
# This file is part of OP25 and part of GNU Radio
#
# OP25 is free software; you can redistribute it and/or modify it
@@ -30,6 +35,7 @@ import math
import numpy
import time
import re
+import Numeric
from gnuradio import audio, eng_notation, fsk4, gr, gru, repeater
from gnuradio import blks2
@@ -88,6 +94,7 @@ class p25_rx_block (stdgui2.std_top_block):
self.usrp = usrp.source_c()
self.channel_rate = self.usrp.adc_freq() / options.decim
except Exception:
+ print "USRP source_c creation failure"
ignore = True
if options.audio:
@@ -109,6 +116,8 @@ class p25_rx_block (stdgui2.std_top_block):
self.datascope_raw_input = False
self.data_scope_connected = False
+ self.constellation_scope_connected = False
+
self.options = options
for i in xrange(len(speeds)):
@@ -192,9 +201,9 @@ class p25_rx_block (stdgui2.std_top_block):
self.fft_state = False
self.c4fm_state = False
- self.cscope_state = False
self.fscope_state = False
self.corr_state = False
+ self.fac_state = False
self.fsk4_demod_connected = False
self.psk_demod_connected = False
self.fsk4_demod_mode = True
@@ -318,12 +327,18 @@ class p25_rx_block (stdgui2.std_top_block):
self.connect_fsk4_demod()
def set_connection(self,
- cscope=False,
fscope=False,
fft=False,
corr=False,
+ fac=False,
c4fm=False):
# assumes that lock is held, or that we are in init
+ if fac != self.fac_state:
+ self.fac_state = fac
+ if fac:
+ self.connect(self.mixer, self.fac_scope)
+ else:
+ self.disconnect(self.mixer, self.fac_scope)
if corr != self.corr_state:
self.corr_state = corr
if corr:
@@ -337,15 +352,6 @@ class p25_rx_block (stdgui2.std_top_block):
else:
self.disconnect(self.symbol_filter, self.correlation_scope)
- if cscope != self.cscope_state:
- self.cscope_state = cscope
- if cscope == 0:
- # self.disconnect(self.diffdec, self.complex_scope)
- self.disconnect(self.clock, self.complex_scope)
- else:
- # self.connect(self.diffdec, self.complex_scope)
- self.connect(self.clock, self.complex_scope)
-
if fscope != self.fscope_state:
self.fscope_state = fscope
if fscope == 0:
@@ -371,30 +377,36 @@ class p25_rx_block (stdgui2.std_top_block):
sel = self.notebook.GetSelection()
self.lock()
self.disconnect_data_scope()
+ self.disconnect_constellation_scope()
if sel == 0: # spectrum
if not self.baseband_input:
self.set_connection(fft=1)
self.disconnect_demods()
- if sel == 1: # c4fm
+ elif sel == 1: # c4fm
self.set_connection(c4fm=1)
self.connect_fsk4_demod()
- if sel == 2: # datascope
+ elif sel == 2: # datascope
self.set_connection()
self.connect_fsk4_demod()
self.connect_data_scope()
- if sel == 3: # constellation (complex)
+ elif sel == 3: # constellation (complex)
if not self.baseband_input:
- self.set_connection(cscope=1)
+ self.set_connection()
self.connect_psk_demod()
- if sel == 4: # demodulated symbols
+ self.connect_constellation_scope()
+ elif sel == 4: # demodulated symbols
self.connect_demods()
self.set_connection(fscope=1)
- if sel == 5: # correlation
+ elif sel == 5: # correlation
self.disconnect_demods()
self.current_speed = self.default_speed_idx # reset speed for corr
self.data_scope.win.radio_box_speed.SetSelection(self.current_speed)
self.connect_fsk4_demod()
self.set_connection(corr=1)
+ elif sel == 6: # fac - fast auto correlation
+ if not self.baseband_input:
+ self.set_connection(fac=1)
+ self.disconnect_demods()
self.unlock()
# initialize the UI
@@ -467,13 +479,19 @@ class p25_rx_block (stdgui2.std_top_block):
self.vbox.Add(self.notebook, 1, wx.EXPAND)
# add spectrum scope
self.spectrum = fftsink2.fft_sink_c(self.notebook, sample_rate = self.channel_rate, fft_size=512, fft_rate=2, average=False, peak_hold=False)
- self.spectrum_plotter = self.spectrum.win.plotter
- self.spectrum_plotter.enable_point_label(False)
+ try:
+ self.spectrum_plotter = self.spectrum.win.plotter
+ except:
+ self.spectrum_plotter = self.spectrum.win.plot
+ #self.spectrum_plotter.enable_point_label(False)
self.spectrum_plotter.Bind(wx.EVT_LEFT_DOWN, self._on_spectrum_left_click)
self.notebook.AddPage(self.spectrum.win, "RF Spectrum")
# add C4FM scope
self.signal_scope = scopesink2.scope_sink_f(self.notebook, sample_rate = self.basic_rate, v_scale=5, t_scale=0.001)
- self.signal_plotter = self.signal_scope.win.plotter
+ try:
+ self.signal_plotter = self.signal_scope.win.plotter
+ except:
+ self.signal_plotter = self.signal_scope.win.graph
self.notebook.AddPage(self.signal_scope.win, "C4FM Signal")
# add datascope
self.data_scope = datascope_sink_f(self.notebook, samples_per_symbol = 10, num_plots = 100)
@@ -485,19 +503,27 @@ class p25_rx_block (stdgui2.std_top_block):
# add complex scope
self.complex_scope = constellation_plot_c(self.notebook, title="Constellation", num_plots=250)
self.notebook.AddPage(self.complex_scope.win, "Constellation")
+ wx.EVT_RADIOBOX(self.complex_scope.win.radio_box_source, 11108, self.source_select)
# add float scope
self.float_scope = scopesink2.scope_sink_f(self.notebook, frame_decim=1, sample_rate=self.symbol_rate, v_scale=1, t_scale=0.05)
- self.float_plotter = self.float_scope.win.plotter
- self.float_scope.win['marker_1'] = 3.0 # set type = large dots
+ try: #gl
+ self.float_plotter = self.float_scope.win.plotter
+ self.float_scope.win['marker_1'] = 3.0 # set type = large dots
+ except: #nongl
+ self.float_plotter = self.float_scope.win.graph
+ self.float_scope.win.set_format_plus()
self.notebook.AddPage(self.float_scope.win, "Demodulated Symbols")
# Traffic snapshot
# self.traffic = TrafficPane(self.notebook)
# self.notebook.AddPage(self.traffic, "Traffic")
- # add float scope
+ # add corr scope
self.correlation_scope = correlation_plot_f(self.notebook, frame_decim=4, sps=10, v_scale=1, t_scale=0.05)
# self.correlation_plotter = self.correlation_scope.win.plotter
wx.EVT_RADIOBOX(self.correlation_scope.win.radio_box_corr, 11105, self.corr_select)
self.notebook.AddPage(self.correlation_scope.win, "Correlation")
+ # add fac scope
+ self.fac_scope = fac_sink_c(self.notebook, fac_size=32768, sample_rate=self.channel_rate, title="Auto Correlation")
+ self.notebook.AddPage(self.fac_scope.win, "Auto Correlation")
# Setup the decoder and report the TUN/TAP device name
msgq = gr.msg_queue(2)
# self.decode_watcher = decode_watcher(msgq, self.traffic)
@@ -943,6 +969,22 @@ class p25_rx_block (stdgui2.std_top_block):
else:
self.connect_psk_demod()
+ def disconnect_constellation_scope(self):
+ if self.constellation_scope_connected:
+ self.disconnect(self.constellation_scope_input, self.complex_scope)
+ self.constellation_scope_connected = False
+ self.constellation_scope_input = None
+
+ def connect_constellation_scope(self):
+ self.disconnect_constellation_scope()
+ sel = self.complex_scope.win.radio_box_source.GetSelection()
+ if sel:
+ self.constellation_scope_input = self.diffdec
+ else:
+ self.constellation_scope_input = self.clock
+ self.constellation_scope_connected = True
+ self.connect(self.constellation_scope_input, self.complex_scope)
+
def disconnect_data_scope(self):
if self.data_scope_connected:
self.disconnect(self.data_scope_input, self.data_scope)
@@ -980,6 +1022,11 @@ class p25_rx_block (stdgui2.std_top_block):
self.set_connection(corr=True)
self.unlock()
+ def source_select(self, evt):
+ self.lock()
+ self.connect_constellation_scope()
+ self.unlock()
+
def speed_select(self, evt):
new_speed = self.data_scope.win.radio_box_speed.GetSelection()
self.lock()
@@ -1553,21 +1600,22 @@ class constellation_plot_input_watcher (threading.Thread):
class constellation_plot_window (wx.Panel):
+ constellation_window_size = wx.DefaultSize
def __init__ (self, info, parent, id = -1,
num_plots=100,
- pos = wx.DefaultPosition, size = wx.DefaultSize, name = ""):
+ pos = wx.DefaultPosition, size = constellation_window_size, name = ""):
wx.Panel.__init__ (self, parent, -1)
self.info = info
- vbox = wx.BoxSizer (wx.VERTICAL)
+ hbox = wx.BoxSizer (wx.HORIZONTAL)
self.graph = constellation_plot_graph_window (info, self, -1, num_plots=num_plots)
- vbox.Add (self.graph, 1, wx.EXPAND)
- vbox.Add (self.make_control_box(), 0, wx.EXPAND)
- vbox.Add (self.make_control2_box(), 0, wx.EXPAND)
+ hbox.Add (self.graph, 1, wx.SHAPED)
+ hbox.Add (self.make_control_box(), 0, wx.EXPAND)
+ hbox.Add (self.make_control2_box(), 0, wx.EXPAND)
- self.sizer = vbox
+ self.sizer = hbox
self.SetSizer (self.sizer)
self.SetAutoLayout (True)
self.sizer.Fit (self)
@@ -1591,10 +1639,20 @@ class constellation_plot_window (wx.Panel):
wx.EVT_BUTTON (self, 11102, self.run_stop)
ctrlbox.Add (run_stop, 0, wx.EXPAND)
- self.radio_box = wx.RadioBox(self, 11103, "Viewpoint", style=wx.RA_SPECIFY_ROWS,
- choices = ["Raw", "Filtered"] )
- self.radio_box.SetToolTipString("Viewpoint Before Or After Symbol Filter")
- ctrlbox.Add (self.radio_box, 0, wx.EXPAND)
+ # self.radio_box.SetToolTipString("Viewpoint Before Or After Symbol Filter")
+
+ self.radio_box_mode = wx.RadioBox(self, 11106, "Mode", style=wx.RA_SPECIFY_ROWS,
+ choices = ["Standard", "Population"] )
+ ctrlbox.Add (self.radio_box_mode, 0, wx.EXPAND)
+
+ self.radio_box_color = wx.RadioBox(self, 11107, "Color", style=wx.RA_SPECIFY_ROWS,
+ choices = ["Mono", "2 Color"] )
+ ctrlbox.Add (self.radio_box_color, 0, wx.EXPAND)
+ wx.EVT_RADIOBOX(self.radio_box_color, 11107, self.color_select)
+
+ self.radio_box_source = wx.RadioBox(self, 11108, "Source", style=wx.RA_SPECIFY_ROWS,
+ choices = ["Direct", "Differential"] )
+ ctrlbox.Add (self.radio_box_source, 0, wx.EXPAND)
ctrlbox.Add ((10, 0) ,1) # stretchy space
@@ -1603,6 +1661,15 @@ class constellation_plot_window (wx.Panel):
def run_stop (self, evt):
self.info.running = not self.info.running
+ def color_select(self, evt):
+ sel = self.radio_box_color.GetSelection()
+ if sel:
+ self.graph.color1 = 'red'
+ self.graph.color2 = 'green'
+ else:
+ self.graph.color1 = 'blue'
+ self.graph.color2 = 'blue'
+
class constellation_plot_graph_window (plot.PlotCanvas):
def __init__ (self, info, parent, id = -1,
@@ -1618,6 +1685,7 @@ class constellation_plot_graph_window (plot.PlotCanvas):
# self.SetBackgroundColour ('black')
self.info = info;
+ self.plot_window = parent
self.total_points = 0
@@ -1629,10 +1697,18 @@ class constellation_plot_graph_window (plot.PlotCanvas):
self.flag = False
- def format_data_orig (self, evt):
+ self.color1 = 'blue'
+ self.color2 = 'blue'
+
+ def format_data (self, evt):
if not self.info.running:
return
+ if self.plot_window.radio_box_mode.GetSelection():
+ self.format_data_pop(evt)
+ else:
+ self.format_data_std(evt)
+ def format_data_std (self, evt):
info = self.info
records = evt.data
nchannels = len (records)
@@ -1655,18 +1731,18 @@ class constellation_plot_graph_window (plot.PlotCanvas):
p0.append(p)
self.flag = not self.flag
- objects.append (plot.PolyMarker (p0, marker='plus', colour='blue'))
- objects.append (plot.PolyMarker (p1, marker='plus', colour='blue'))
+ objects.append (plot.PolyMarker (p0, marker='plus', colour=self.color1))
+ objects.append (plot.PolyMarker (p1, marker='plus', colour=self.color2))
graphics = plot.PlotGraphics (objects,
- title='Data Scope',
+ title='Constellation',
xLabel = 'I', yLabel = 'Q')
x_range = (-1.0, 1.0)
y_range = (-1.0, 1.0)
self.Draw (graphics, xAxis=x_range, yAxis=y_range)
- def format_data (self, evt):
+ def format_data_pop (self, evt):
if not self.info.running:
return
@@ -1679,7 +1755,6 @@ class constellation_plot_graph_window (plot.PlotCanvas):
self.SetXUseScopeTicks (True) # use 10 divisions, no labels
objects = []
- colors = ['red','orange','yellow','green','blue','violet','cyan','magenta','brown','black']
r = records[0] # input data
l = len(r) / 2
@@ -1732,13 +1807,11 @@ class constellation_plot_graph_window (plot.PlotCanvas):
sp = p
p1.append(p)
p1.append(sp)
- # objects.append (plot.PolyMarker (p0, marker='point', colour='red'))
- # objects.append (plot.PolyMarker (p1, marker='point', colour='green'))
- objects.append (plot.PolyLine (p0, colour='red', legend=''))
- objects.append (plot.PolyLine (p1, colour='green', legend=''))
+ objects.append (plot.PolyLine (p0, colour=self.color1, legend=''))
+ objects.append (plot.PolyLine (p1, colour=self.color2, legend=''))
graphics = plot.PlotGraphics (objects,
- title='Data Scope',
+ title='Constellation',
xLabel = 'I', yLabel = 'Q')
x_range = (-2.5, 2.5)
@@ -2003,6 +2076,459 @@ class correlation_plot_graph_window (plot.PlotCanvas):
y_range = (-800.0, 800.0)
self.Draw (graphics, xAxis=x_range, yAxis=y_range)
+#
+# following code copied from radiorausch file facsink.py
+# source: http://sites.google.com/site/radiorausch/
+#
+# modified Jul. 2011 to current GR KA1RBI (to fix error messages)
+#
+# Copyright 2003,2004,2005,2006 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+# default_facsink_size = (640,240)
+default_facsink_size = wx.DefaultSize
+default_fac_rate = gr.prefs().get_long('wxgui', 'fac_rate', 3) # was 15
+
+class fac_sink_base(object):
+ def __init__(self, input_is_real=False, baseband_freq=0, y_per_div=10, ref_level=50,
+ sample_rate=1, fac_size=512,
+ fac_rate=default_fac_rate,
+ average=False, avg_alpha=None, title='', peak_hold=False):
+
+ # initialize common attributes
+ self.baseband_freq = baseband_freq
+ self.y_divs = 8
+ self.y_per_div=y_per_div
+ self.ref_level = ref_level
+ self.sample_rate = sample_rate
+ self.fac_size = fac_size
+ self.fac_rate = fac_rate
+ self.average = average
+ if avg_alpha is None:
+ self.avg_alpha = 0.20 / fac_rate # averaging needed to be slowed down for very slow rates
+ else:
+ self.avg_alpha = avg_alpha
+ self.title = title
+ self.peak_hold = peak_hold
+ self.input_is_real = input_is_real
+ self.msgq = gr.msg_queue(2) # queue that holds a maximum of 2 messages
+
+ def set_y_per_div(self, y_per_div):
+ self.y_per_div = y_per_div
+
+ def set_ref_level(self, ref_level):
+ self.ref_level = ref_level
+
+ def set_average(self, average):
+ self.average = average
+ if average:
+ self.avg.set_taps(self.avg_alpha)
+ self.set_peak_hold(False)
+ else:
+ self.avg.set_taps(1.0)
+
+ def set_peak_hold(self, enable):
+ self.peak_hold = enable
+ if enable:
+ self.set_average(False)
+ self.win.set_peak_hold(enable)
+
+ def set_avg_alpha(self, avg_alpha):
+ self.avg_alpha = avg_alpha
+
+ def set_baseband_freq(self, baseband_freq):
+ self.baseband_freq = baseband_freq
+
+ def set_sample_rate(self, sample_rate):
+ self.sample_rate = sample_rate
+ self._set_n()
+
+ def _set_n(self):
+ self.one_in_n.set_n(max(1, int(self.sample_rate/self.fac_size/self.fac_rate)))
+
+
+class fac_sink_f(gr.hier_block2, fac_sink_base):
+ def __init__(self, parent, baseband_freq=0,
+ y_per_div=10, ref_level=50, sample_rate=1, fac_size=512,
+ fac_rate=default_fac_rate,
+ average=False, avg_alpha=None,
+ title='', size=default_facsink_size, peak_hold=False):
+
+ fac_sink_base.__init__(self, input_is_real=True, baseband_freq=baseband_freq,
+ y_per_div=y_per_div, ref_level=ref_level,
+ sample_rate=sample_rate, fac_size=fac_size,
+ fac_rate=fac_rate,
+ average=average, avg_alpha=avg_alpha, title=title,
+ peak_hold=peak_hold)
+
+ s2p = gr.stream_to_vector(gr.sizeof_float, self.fac_size)
+ self.one_in_n = gr.keep_one_in_n(gr.sizeof_float * self.fac_size,
+ max(1, int(self.sample_rate/self.fac_size/self.fac_rate)))
+
+
+ # windowing removed...
+
+ fac = gr.fft_vfc(self.fac_size, True, ())
+
+ c2mag = gr.complex_to_mag(self.fac_size)
+ self.avg = gr.single_pole_iir_filter_ff(1.0, self.fac_size)
+
+ #
+ fac_fac = gr.fft_vfc(self.fac_size, True, ())
+ fac_c2mag = gr.complex_to_mag(fac_size)
+
+
+ # FIXME We need to add 3dB to all bins but the DC bin
+ log = gr.nlog10_ff(20, self.fac_size,
+ -20*math.log10(self.fac_size) )
+ sink = gr.message_sink(gr.sizeof_float * self.fac_size, self.msgq, True)
+
+ self.connect(self, s2p, self.one_in_n, fac, c2mag, fac_fac, fac_c2mag, self.avg, log, sink)
+ # gr.hier_block.__init__(self, fg, s2p, sink)
+ gr.hier_block2.__init__(self, "fac_sink_f",
+ gr.io_signature(1, 1, gr.sizeof_float),
+ gr.io_signature(0, 0, 0))
+
+ self.win = fac_window(self, parent, size=size)
+ self.set_average(self.average)
+
+
+
+class fac_sink_c(gr.hier_block2, fac_sink_base):
+ def __init__(self, parent, baseband_freq=0,
+ y_per_div=10, ref_level=90, sample_rate=1, fac_size=512,
+ fac_rate=default_fac_rate,
+ average=False, avg_alpha=None,
+ title='', size=default_facsink_size, peak_hold=False):
+
+ fac_sink_base.__init__(self, input_is_real=False, baseband_freq=baseband_freq,
+ y_per_div=y_per_div, ref_level=ref_level,
+ sample_rate=sample_rate, fac_size=fac_size,
+ fac_rate=fac_rate,
+ average=average, avg_alpha=avg_alpha, title=title,
+ peak_hold=peak_hold)
+ gr.hier_block2.__init__(self, "fac_sink_c",
+ gr.io_signature(1, 1, gr.sizeof_gr_complex),
+ gr.io_signature(0, 0, 0))
+
+ #s2p = gr.stream_to_vector(gr.sizeof_gr_complex, self.fac_size)
+ s2p = repeater.s2v(gr.sizeof_gr_complex, self.fac_size)
+ self.one_in_n = gr.keep_one_in_n(gr.sizeof_gr_complex * self.fac_size,
+ max(1, int(self.sample_rate/self.fac_size/self.fac_rate)))
+
+
+ # windowing removed ...
+
+ fac = gr.fft_vcc(self.fac_size, True, ())
+ c2mag = gr.complex_to_mag(fac_size)
+
+ # Things go off into the weeds if we try for an inverse FFT so a forward FFT will have to do...
+ fac_fac = gr.fft_vfc(self.fac_size, True, ())
+ fac_c2mag = gr.complex_to_mag(fac_size)
+
+
+ self.avg = gr.single_pole_iir_filter_ff(1.0, fac_size)
+
+ log = gr.nlog10_ff(20, self.fac_size,
+ -20*math.log10(self.fac_size) ) # - 20*math.log10(norm) ) # - self.avg[0] )
+ sink = gr.message_sink(gr.sizeof_float * fac_size, self.msgq, True)
+
+ self.connect(self, s2p, self.one_in_n, fac, c2mag, fac_fac, fac_c2mag, self.avg)
+ self.connect(self.avg, log, sink)
+
+ # gr.hier_block.__init__(self, fg, s2p, sink)
+
+ self.win = fac_window(self, parent, size=size)
+ self.set_average(self.average)
+
+
+# ------------------------------------------------------------------------
+
+fac_myDATA_EVENT = wx.NewEventType()
+fac_EVT_DATA_EVENT = wx.PyEventBinder (fac_myDATA_EVENT, 0)
+
+
+class fac_DataEvent(wx.PyEvent):
+ def __init__(self, data):
+ wx.PyEvent.__init__(self)
+ self.SetEventType (fac_myDATA_EVENT)
+ self.data = data
+
+ def Clone (self):
+ self.__class__ (self.GetId())
+
+
+class fac_input_watcher (threading.Thread):
+ def __init__ (self, msgq, fac_size, event_receiver, **kwds):
+ threading.Thread.__init__ (self, **kwds)
+ self.setDaemon (1)
+ self.msgq = msgq
+ self.fac_size = fac_size
+ self.event_receiver = event_receiver
+ self.keep_running = True
+ self.start ()
+
+ def run (self):
+ while (self.keep_running):
+ msg = self.msgq.delete_head() # blocking read of message queue
+ itemsize = int(msg.arg1())
+ nitems = int(msg.arg2())
+
+ s = msg.to_string() # get the body of the msg as a string
+
+ # There may be more than one fac frame in the message.
+ # If so, we take only the last one
+ if nitems > 1:
+ start = itemsize * (nitems - 1)
+ s = s[start:start+itemsize]
+
+ complex_data = Numeric.fromstring (s, Numeric.Float32)
+ de = fac_DataEvent (complex_data)
+ wx.PostEvent (self.event_receiver, de)
+ del de
+
+
+class fac_window (plot.PlotCanvas):
+ def __init__ (self, facsink, parent, id = -1,
+ pos = wx.DefaultPosition, size = wx.DefaultSize,
+ style = wx.DEFAULT_FRAME_STYLE, name = ""):
+ plot.PlotCanvas.__init__ (self, parent, id, pos, size, style, name)
+
+ self.y_range = None
+ self.facsink = facsink
+ self.peak_hold = False
+ self.peak_vals = None
+
+ self.SetEnableGrid (True)
+ # self.SetEnableZoom (True)
+ # self.SetBackgroundColour ('black')
+
+ self.build_popup_menu()
+
+ fac_EVT_DATA_EVENT (self, self.set_data)
+ wx.EVT_CLOSE (self, self.on_close_window)
+ self.Bind(wx.EVT_RIGHT_UP, self.on_right_click)
+
+ self.input_watcher = fac_input_watcher(facsink.msgq, facsink.fac_size, self)
+
+
+ def on_close_window (self, event):
+ print "fac_window:on_close_window"
+ self.keep_running = False
+
+
+ def set_data (self, evt):
+ dB = evt.data
+ L = len (dB)
+
+ if self.peak_hold:
+ if self.peak_vals is None:
+ self.peak_vals = dB
+ else:
+ self.peak_vals = Numeric.maximum(dB, self.peak_vals)
+ dB = self.peak_vals
+
+ x = max(abs(self.facsink.sample_rate), abs(self.facsink.baseband_freq))
+ sf = 1000.0
+ units = "ms"
+
+ x_vals = ((Numeric.arrayrange (L/2)
+ * ( (sf / self.facsink.sample_rate ) )) )
+ points = Numeric.zeros((len(x_vals), 2), Numeric.Float64)
+ points[:,0] = x_vals
+ points[:,1] = dB[0:L/2]
+
+
+ lines = plot.PolyLine (points, colour='DARKRED')
+
+
+ graphics = plot.PlotGraphics ([lines],
+ title=self.facsink.title,
+ xLabel = units, yLabel = "dB")
+
+ self.Draw (graphics, xAxis=None, yAxis=self.y_range)
+ self.update_y_range ()
+
+ def set_peak_hold(self, enable):
+ self.peak_hold = enable
+ self.peak_vals = None
+
+ def update_y_range (self):
+ ymax = self.facsink.ref_level
+ ymin = self.facsink.ref_level - self.facsink.y_per_div * self.facsink.y_divs
+ self.y_range = self._axisInterval ('min', ymin, ymax)
+
+ def on_average(self, evt):
+ # print "on_average"
+ self.facsink.set_average(evt.IsChecked())
+
+ def on_peak_hold(self, evt):
+ # print "on_peak_hold"
+ self.facsink.set_peak_hold(evt.IsChecked())
+
+ def on_incr_ref_level(self, evt):
+ # print "on_incr_ref_level"
+ self.facsink.set_ref_level(self.facsink.ref_level
+ + self.facsink.y_per_div)
+
+ def on_decr_ref_level(self, evt):
+ # print "on_decr_ref_level"
+ self.facsink.set_ref_level(self.facsink.ref_level
+ - self.facsink.y_per_div)
+
+ def on_incr_y_per_div(self, evt):
+ # print "on_incr_y_per_div"
+ self.facsink.set_y_per_div(next_up(self.facsink.y_per_div, (1,2,5,10,20)))
+
+ def on_decr_y_per_div(self, evt):
+ # print "on_decr_y_per_div"
+ self.facsink.set_y_per_div(next_down(self.facsink.y_per_div, (1,2,5,10,20)))
+
+ def on_y_per_div(self, evt):
+ # print "on_y_per_div"
+ Id = evt.GetId()
+ if Id == self.id_y_per_div_1:
+ self.facsink.set_y_per_div(1)
+ elif Id == self.id_y_per_div_2:
+ self.facsink.set_y_per_div(2)
+ elif Id == self.id_y_per_div_5:
+ self.facsink.set_y_per_div(5)
+ elif Id == self.id_y_per_div_10:
+ self.facsink.set_y_per_div(10)
+ elif Id == self.id_y_per_div_20:
+ self.facsink.set_y_per_div(20)
+
+
+ def on_right_click(self, event):
+ menu = self.popup_menu
+ for id, pred in self.checkmarks.items():
+ item = menu.FindItemById(id)
+ item.Check(pred())
+ self.PopupMenu(menu, event.GetPosition())
+
+
+ def build_popup_menu(self):
+ self.id_incr_ref_level = wx.NewId()
+ self.id_decr_ref_level = wx.NewId()
+ self.id_incr_y_per_div = wx.NewId()
+ self.id_decr_y_per_div = wx.NewId()
+ self.id_y_per_div_1 = wx.NewId()
+ self.id_y_per_div_2 = wx.NewId()
+ self.id_y_per_div_5 = wx.NewId()
+ self.id_y_per_div_10 = wx.NewId()
+ self.id_y_per_div_20 = wx.NewId()
+ self.id_average = wx.NewId()
+ self.id_peak_hold = wx.NewId()
+
+ self.Bind(wx.EVT_MENU, self.on_average, id=self.id_average)
+ self.Bind(wx.EVT_MENU, self.on_peak_hold, id=self.id_peak_hold)
+ self.Bind(wx.EVT_MENU, self.on_incr_ref_level, id=self.id_incr_ref_level)
+ self.Bind(wx.EVT_MENU, self.on_decr_ref_level, id=self.id_decr_ref_level)
+ self.Bind(wx.EVT_MENU, self.on_incr_y_per_div, id=self.id_incr_y_per_div)
+ self.Bind(wx.EVT_MENU, self.on_decr_y_per_div, id=self.id_decr_y_per_div)
+ self.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_1)
+ self.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_2)
+ self.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_5)
+ self.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_10)
+ self.Bind(wx.EVT_MENU, self.on_y_per_div, id=self.id_y_per_div_20)
+
+
+ # make a menu
+ menu = wx.Menu()
+ self.popup_menu = menu
+ menu.AppendCheckItem(self.id_average, "Average")
+ menu.AppendCheckItem(self.id_peak_hold, "Peak Hold")
+ menu.Append(self.id_incr_ref_level, "Incr Ref Level")
+ menu.Append(self.id_decr_ref_level, "Decr Ref Level")
+ # menu.Append(self.id_incr_y_per_div, "Incr dB/div")
+ # menu.Append(self.id_decr_y_per_div, "Decr dB/div")
+ menu.AppendSeparator()
+ # we'd use RadioItems for these, but they're not supported on Mac
+ menu.AppendCheckItem(self.id_y_per_div_1, "1 dB/div")
+ menu.AppendCheckItem(self.id_y_per_div_2, "2 dB/div")
+ menu.AppendCheckItem(self.id_y_per_div_5, "5 dB/div")
+ menu.AppendCheckItem(self.id_y_per_div_10, "10 dB/div")
+ menu.AppendCheckItem(self.id_y_per_div_20, "20 dB/div")
+
+ self.checkmarks = {
+ self.id_average : lambda : self.facsink.average,
+ self.id_peak_hold : lambda : self.facsink.peak_hold,
+ self.id_y_per_div_1 : lambda : self.facsink.y_per_div == 1,
+ self.id_y_per_div_2 : lambda : self.facsink.y_per_div == 2,
+ self.id_y_per_div_5 : lambda : self.facsink.y_per_div == 5,
+ self.id_y_per_div_10 : lambda : self.facsink.y_per_div == 10,
+ self.id_y_per_div_20 : lambda : self.facsink.y_per_div == 20,
+ }
+
+
+def next_up(v, seq):
+ """
+ Return the first item in seq that is > v.
+ """
+ for s in seq:
+ if s > v:
+ return s
+ return v
+
+def next_down(v, seq):
+ """
+ Return the last item in seq that is < v.
+ """
+ rseq = list(seq[:])
+ rseq.reverse()
+
+ for s in rseq:
+ if s < v:
+ return s
+ return v
+
+
+# ----------------------------------------------------------------
+# Deprecated interfaces
+# ----------------------------------------------------------------
+
+# returns (block, win).
+# block requires a single input stream of float
+# win is a subclass of wxWindow
+
+def make_fac_sink_f(fg, parent, title, fac_size, input_rate, ymin = 0, ymax=50):
+
+ block = fac_sink_f(fg, parent, title=title, fac_size=fac_size, sample_rate=input_rate,
+ y_per_div=(ymax - ymin)/8, ref_level=ymax)
+ return (block, block.win)
+
+# returns (block, win).
+# block requires a single input stream of gr_complex
+# win is a subclass of wxWindow
+
+def make_fac_sink_c(fg, parent, title, fac_size, input_rate, ymin=0, ymax=50):
+ block = fac_sink_c(fg, parent, title=title, fac_size=fac_size, sample_rate=input_rate,
+ y_per_div=(ymax - ymin)/8, ref_level=ymax)
+ return (block, block.win)
+
+
+# ----------------------------------------------------------------
+# Standalone test app - deleted
+# ----------------------------------------------------------------
+
+
############################################################################
# Start the receiver