summaryrefslogtreecommitdiff
path: root/gnuradio-core/src/python/gnuradio/gruimpl
diff options
context:
space:
mode:
authorjcorgan <jcorgan@221aa14e-8319-0410-a670-987f0aec2ac5>2006-08-03 04:51:51 +0000
committerjcorgan <jcorgan@221aa14e-8319-0410-a670-987f0aec2ac5>2006-08-03 04:51:51 +0000
commit5d69a524f81f234b3fbc41d49ba18d6f6886baba (patch)
treeb71312bf7f1e8d10fef0f3ac6f28784065e73e72 /gnuradio-core/src/python/gnuradio/gruimpl
Houston, we have a trunk.
git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@3122 221aa14e-8319-0410-a670-987f0aec2ac5
Diffstat (limited to 'gnuradio-core/src/python/gnuradio/gruimpl')
-rw-r--r--gnuradio-core/src/python/gnuradio/gruimpl/Makefile.am40
-rw-r--r--gnuradio-core/src/python/gnuradio/gruimpl/__init__.py1
-rw-r--r--gnuradio-core/src/python/gnuradio/gruimpl/crc.py36
-rw-r--r--gnuradio-core/src/python/gnuradio/gruimpl/freqz.py344
-rwxr-xr-xgnuradio-core/src/python/gnuradio/gruimpl/gnuplot_freqz.py82
-rw-r--r--gnuradio-core/src/python/gnuradio/gruimpl/hexint.py32
-rw-r--r--gnuradio-core/src/python/gnuradio/gruimpl/listmisc.py29
-rwxr-xr-xgnuradio-core/src/python/gnuradio/gruimpl/lmx2306.py186
-rw-r--r--gnuradio-core/src/python/gnuradio/gruimpl/mathmisc.py33
-rw-r--r--gnuradio-core/src/python/gnuradio/gruimpl/os_read_exactly.py36
-rw-r--r--gnuradio-core/src/python/gnuradio/gruimpl/sdr_1000.py84
-rw-r--r--gnuradio-core/src/python/gnuradio/gruimpl/seq_with_cursor.py77
-rw-r--r--gnuradio-core/src/python/gnuradio/gruimpl/socket_stuff.py56
13 files changed, 1036 insertions, 0 deletions
diff --git a/gnuradio-core/src/python/gnuradio/gruimpl/Makefile.am b/gnuradio-core/src/python/gnuradio/gruimpl/Makefile.am
new file mode 100644
index 0000000000..06eb7a1f90
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/gruimpl/Makefile.am
@@ -0,0 +1,40 @@
+#
+# Copyright 2005 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.
+#
+
+include $(top_srcdir)/Makefile.common
+
+grupythondir = $(grpythondir)/gruimpl
+
+grupython_PYTHON = \
+ __init__.py \
+ crc.py \
+ freqz.py \
+ gnuplot_freqz.py \
+ hexint.py \
+ listmisc.py \
+ mathmisc.py \
+ lmx2306.py \
+ os_read_exactly.py \
+ sdr_1000.py \
+ seq_with_cursor.py \
+ socket_stuff.py
+
+CLEANFILES = *.pyc
diff --git a/gnuradio-core/src/python/gnuradio/gruimpl/__init__.py b/gnuradio-core/src/python/gnuradio/gruimpl/__init__.py
new file mode 100644
index 0000000000..a4917cf64c
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/gruimpl/__init__.py
@@ -0,0 +1 @@
+# make this a package
diff --git a/gnuradio-core/src/python/gnuradio/gruimpl/crc.py b/gnuradio-core/src/python/gnuradio/gruimpl/crc.py
new file mode 100644
index 0000000000..6a97c81b52
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/gruimpl/crc.py
@@ -0,0 +1,36 @@
+#
+# Copyright 2005 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.
+#
+
+from gnuradio import gr
+from hexint import *
+import struct
+
+def gen_and_append_crc32(s):
+ crc = gr.crc32(s)
+ return s + struct.pack(">I", hexint(crc))
+
+def check_crc32(s):
+ msg = s[:-4]
+ #print "msg = '%s'" % (msg,)
+ actual = gr.crc32(msg)
+ (expected,) = struct.unpack(">I", s[-4:])
+ # print "actual =", hex(actual), "expected =", hex(expected)
+ return (actual == expected, msg)
diff --git a/gnuradio-core/src/python/gnuradio/gruimpl/freqz.py b/gnuradio-core/src/python/gnuradio/gruimpl/freqz.py
new file mode 100644
index 0000000000..21704944c1
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/gruimpl/freqz.py
@@ -0,0 +1,344 @@
+#!/usr/bin/env python
+#
+# Copyright 2005 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.
+#
+
+# This code lifted from various parts of www.scipy.org -eb 2005-01-24
+
+# Copyright (c) 2001, 2002 Enthought, Inc.
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# a. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# b. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# c. Neither the name of the Enthought nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+# DAMAGE.
+#
+
+__all__ = ['freqz']
+
+import Numeric
+from Numeric import *
+Num=Numeric
+
+def atleast_1d(*arys):
+ """ Force a sequence of arrays to each be at least 1D.
+
+ Description:
+ Force an array to be at least 1D. If an array is 0D, the
+ array is converted to a single row of values. Otherwise,
+ the array is unaltered.
+ Arguments:
+ *arys -- arrays to be converted to 1 or more dimensional array.
+ Returns:
+ input array converted to at least 1D array.
+ """
+ res = []
+ for ary in arys:
+ ary = asarray(ary)
+ if len(ary.shape) == 0:
+ result = Numeric.array([ary[0]])
+ else:
+ result = ary
+ res.append(result)
+ if len(res) == 1:
+ return res[0]
+ else:
+ return res
+
+
+def polyval(p,x):
+ """Evaluate the polynomial p at x. If x is a polynomial then composition.
+
+ Description:
+
+ If p is of length N, this function returns the value:
+ p[0]*(x**N-1) + p[1]*(x**N-2) + ... + p[N-2]*x + p[N-1]
+
+ x can be a sequence and p(x) will be returned for all elements of x.
+ or x can be another polynomial and the composite polynomial p(x) will be
+ returned.
+ """
+ p = asarray(p)
+ if isinstance(x,poly1d):
+ y = 0
+ else:
+ x = asarray(x)
+ y = Numeric.zeros(x.shape,x.typecode())
+ for i in range(len(p)):
+ y = x * y + p[i]
+ return y
+
+class poly1d:
+ """A one-dimensional polynomial class.
+
+ p = poly1d([1,2,3]) constructs the polynomial x**2 + 2 x + 3
+
+ p(0.5) evaluates the polynomial at the location
+ p.r is a list of roots
+ p.c is the coefficient array [1,2,3]
+ p.order is the polynomial order (after leading zeros in p.c are removed)
+ p[k] is the coefficient on the kth power of x (backwards from
+ sequencing the coefficient array.
+
+ polynomials can be added, substracted, multplied and divided (returns
+ quotient and remainder).
+ asarray(p) will also give the coefficient array, so polynomials can
+ be used in all functions that accept arrays.
+ """
+ def __init__(self, c_or_r, r=0):
+ if isinstance(c_or_r,poly1d):
+ for key in c_or_r.__dict__.keys():
+ self.__dict__[key] = c_or_r.__dict__[key]
+ return
+ if r:
+ c_or_r = poly(c_or_r)
+ c_or_r = atleast_1d(c_or_r)
+ if len(c_or_r.shape) > 1:
+ raise ValueError, "Polynomial must be 1d only."
+ c_or_r = trim_zeros(c_or_r, trim='f')
+ if len(c_or_r) == 0:
+ c_or_r = Numeric.array([0])
+ self.__dict__['coeffs'] = c_or_r
+ self.__dict__['order'] = len(c_or_r) - 1
+
+ def __array__(self,t=None):
+ if t:
+ return asarray(self.coeffs,t)
+ else:
+ return asarray(self.coeffs)
+
+ def __coerce__(self,other):
+ return None
+
+ def __repr__(self):
+ vals = repr(self.coeffs)
+ vals = vals[6:-1]
+ return "poly1d(%s)" % vals
+
+ def __len__(self):
+ return self.order
+
+ def __str__(self):
+ N = self.order
+ thestr = "0"
+ for k in range(len(self.coeffs)):
+ coefstr ='%.4g' % abs(self.coeffs[k])
+ if coefstr[-4:] == '0000':
+ coefstr = coefstr[:-5]
+ power = (N-k)
+ if power == 0:
+ if coefstr != '0':
+ newstr = '%s' % (coefstr,)
+ else:
+ if k == 0:
+ newstr = '0'
+ else:
+ newstr = ''
+ elif power == 1:
+ if coefstr == '0':
+ newstr = ''
+ elif coefstr == '1':
+ newstr = 'x'
+ else:
+ newstr = '%s x' % (coefstr,)
+ else:
+ if coefstr == '0':
+ newstr = ''
+ elif coefstr == '1':
+ newstr = 'x**%d' % (power,)
+ else:
+ newstr = '%s x**%d' % (coefstr, power)
+
+ if k > 0:
+ if newstr != '':
+ if self.coeffs[k] < 0:
+ thestr = "%s - %s" % (thestr, newstr)
+ else:
+ thestr = "%s + %s" % (thestr, newstr)
+ elif (k == 0) and (newstr != '') and (self.coeffs[k] < 0):
+ thestr = "-%s" % (newstr,)
+ else:
+ thestr = newstr
+ return _raise_power(thestr)
+
+
+ def __call__(self, val):
+ return polyval(self.coeffs, val)
+
+ def __mul__(self, other):
+ if isscalar(other):
+ return poly1d(self.coeffs * other)
+ else:
+ other = poly1d(other)
+ return poly1d(polymul(self.coeffs, other.coeffs))
+
+ def __rmul__(self, other):
+ if isscalar(other):
+ return poly1d(other * self.coeffs)
+ else:
+ other = poly1d(other)
+ return poly1d(polymul(self.coeffs, other.coeffs))
+
+ def __add__(self, other):
+ other = poly1d(other)
+ return poly1d(polyadd(self.coeffs, other.coeffs))
+
+ def __radd__(self, other):
+ other = poly1d(other)
+ return poly1d(polyadd(self.coeffs, other.coeffs))
+
+ def __pow__(self, val):
+ if not isscalar(val) or int(val) != val or val < 0:
+ raise ValueError, "Power to non-negative integers only."
+ res = [1]
+ for k in range(val):
+ res = polymul(self.coeffs, res)
+ return poly1d(res)
+
+ def __sub__(self, other):
+ other = poly1d(other)
+ return poly1d(polysub(self.coeffs, other.coeffs))
+
+ def __rsub__(self, other):
+ other = poly1d(other)
+ return poly1d(polysub(other.coeffs, self.coeffs))
+
+ def __div__(self, other):
+ if isscalar(other):
+ return poly1d(self.coeffs/other)
+ else:
+ other = poly1d(other)
+ return map(poly1d,polydiv(self.coeffs, other.coeffs))
+
+ def __rdiv__(self, other):
+ if isscalar(other):
+ return poly1d(other/self.coeffs)
+ else:
+ other = poly1d(other)
+ return map(poly1d,polydiv(other.coeffs, self.coeffs))
+
+ def __setattr__(self, key, val):
+ raise ValueError, "Attributes cannot be changed this way."
+
+ def __getattr__(self, key):
+ if key in ['r','roots']:
+ return roots(self.coeffs)
+ elif key in ['c','coef','coefficients']:
+ return self.coeffs
+ elif key in ['o']:
+ return self.order
+ else:
+ return self.__dict__[key]
+
+ def __getitem__(self, val):
+ ind = self.order - val
+ if val > self.order:
+ return 0
+ if val < 0:
+ return 0
+ return self.coeffs[ind]
+
+ def __setitem__(self, key, val):
+ ind = self.order - key
+ if key < 0:
+ raise ValueError, "Does not support negative powers."
+ if key > self.order:
+ zr = Numeric.zeros(key-self.order,self.coeffs.typecode())
+ self.__dict__['coeffs'] = Numeric.concatenate((zr,self.coeffs))
+ self.__dict__['order'] = key
+ ind = 0
+ self.__dict__['coeffs'][ind] = val
+ return
+
+ def integ(self, m=1, k=0):
+ return poly1d(polyint(self.coeffs,m=m,k=k))
+
+ def deriv(self, m=1):
+ return poly1d(polyder(self.coeffs,m=m))
+
+def freqz(b, a, worN=None, whole=0, plot=None):
+ """Compute frequency response of a digital filter.
+
+ Description:
+
+ Given the numerator (b) and denominator (a) of a digital filter compute
+ its frequency response.
+
+ jw -jw -jmw
+ jw B(e) b[0] + b[1]e + .... + b[m]e
+ H(e) = ---- = ------------------------------------
+ jw -jw -jnw
+ A(e) a[0] + a[2]e + .... + a[n]e
+
+ Inputs:
+
+ b, a --- the numerator and denominator of a linear filter.
+ worN --- If None, then compute at 512 frequencies around the unit circle.
+ If a single integer, the compute at that many frequencies.
+ Otherwise, compute the response at frequencies given in worN
+ whole -- Normally, frequencies are computed from 0 to pi (upper-half of
+ unit-circle. If whole is non-zero compute frequencies from 0
+ to 2*pi.
+
+ Outputs: (h,w)
+
+ h -- The frequency response.
+ w -- The frequencies at which h was computed.
+ """
+ b, a = map(atleast_1d, (b,a))
+ if whole:
+ lastpoint = 2*pi
+ else:
+ lastpoint = pi
+ if worN is None:
+ N = 512
+ w = Num.arange(0,lastpoint,lastpoint/N)
+ elif isinstance(worN, types.IntType):
+ N = worN
+ w = Num.arange(0,lastpoint,lastpoint/N)
+ else:
+ w = worN
+ w = atleast_1d(w)
+ zm1 = exp(-1j*w)
+ h = polyval(b[::-1], zm1) / polyval(a[::-1], zm1)
+ # if not plot is None:
+ # plot(w, h)
+ return h, w
diff --git a/gnuradio-core/src/python/gnuradio/gruimpl/gnuplot_freqz.py b/gnuradio-core/src/python/gnuradio/gruimpl/gnuplot_freqz.py
new file mode 100755
index 0000000000..5a117605a1
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/gruimpl/gnuplot_freqz.py
@@ -0,0 +1,82 @@
+#!/usr/bin/env python
+#
+# Copyright 2005 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.
+#
+
+__all__ = ['gnuplot_freqz']
+
+import tempfile
+import os
+import math
+import Numeric
+
+from gnuradio import gr
+from gnuradio.gruimpl.freqz import freqz
+
+
+def gnuplot_freqz (hw, Fs=None, logfreq=False):
+
+ """hw is a tuple of the form (h, w) where h is sequence of complex
+ freq responses, and w is a sequence of corresponding frequency
+ points. Plot the frequency response using gnuplot. If Fs is
+ provide, use it as the sampling frequency, else use 2*pi.
+
+ Returns a handle to the gnuplot graph. When the handle is reclaimed
+ the graph is torn down."""
+
+ data_file = tempfile.NamedTemporaryFile ()
+ cmd_file = os.popen ('gnuplot', 'w')
+
+ h, w = hw
+ ampl = 20 * Numeric.log10 (Numeric.absolute (h) + 1e-9)
+ phase = map (lambda x: math.atan2 (x.imag, x.real), h)
+
+ if Fs:
+ w *= (Fs/(2*math.pi))
+
+ for freq, a, ph in zip (w, ampl, phase):
+ data_file.write ("%g\t%g\t%g\n" % (freq, a, ph))
+
+ data_file.flush ()
+
+ cmd_file.write ("set grid\n")
+ if logfreq:
+ cmd_file.write ("set logscale x\n")
+ else:
+ cmd_file.write ("unset logscale x\n")
+ cmd_file.write ("plot '%s' using 1:2 with lines\n" % (data_file.name,))
+ cmd_file.flush ()
+
+ return (cmd_file, data_file)
+
+
+def test_plot ():
+ sample_rate = 2.0e6
+ taps = gr.firdes.low_pass (1.0, # gain
+ sample_rate, # sampling rate
+ 200e3, # low pass cutoff freq
+ 100e3, # width of trans. band
+ gr.firdes.WIN_HAMMING)
+ # print len (taps)
+ return gnuplot_freqz (freqz (taps, 1), sample_rate)
+
+if __name__ == '__main__':
+ handle = test_plot ()
+ raw_input ('Press Enter to continue: ')
diff --git a/gnuradio-core/src/python/gnuradio/gruimpl/hexint.py b/gnuradio-core/src/python/gnuradio/gruimpl/hexint.py
new file mode 100644
index 0000000000..1220755cbc
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/gruimpl/hexint.py
@@ -0,0 +1,32 @@
+#
+# Copyright 2005 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.
+#
+
+def hexint(mask):
+ """
+ Convert unsigned masks into signed ints.
+
+ This allows us to use hex constants like 0xf0f0f0f2 when talking to
+ our hardware and not get screwed by them getting treated as python
+ longs.
+ """
+ if mask >= 2**31:
+ return int(mask-2**32)
+ return mask
diff --git a/gnuradio-core/src/python/gnuradio/gruimpl/listmisc.py b/gnuradio-core/src/python/gnuradio/gruimpl/listmisc.py
new file mode 100644
index 0000000000..857e417f26
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/gruimpl/listmisc.py
@@ -0,0 +1,29 @@
+#
+# Copyright 2005 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.
+#
+
+def list_reverse(x):
+ """
+ Return a copy of x that is reverse order.
+ """
+ r = list(x)
+ r.reverse()
+ return r
+
diff --git a/gnuradio-core/src/python/gnuradio/gruimpl/lmx2306.py b/gnuradio-core/src/python/gnuradio/gruimpl/lmx2306.py
new file mode 100755
index 0000000000..b46c896f73
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/gruimpl/lmx2306.py
@@ -0,0 +1,186 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+
+'''Control National LMX2306 based frequency synthesizer'''
+
+from gnuradio import gr
+from gnuradio import eng_notation
+from gnuradio.eng_option import eng_option
+from optparse import OptionParser
+
+# bottom two bits of 21 bit word select which register to program
+
+R_REG = 0x0
+AB_REG = 0x1
+F_REG = 0x2
+
+F_counter_reset = (1 << 2)
+F_phase_detector_polarity = (1 << 7)
+
+F_LD_tri_state = (0 << 4)
+F_LD_R_divider_output = (4 << 4)
+F_LD_N_divider_output = (2 << 4)
+F_LD_serial_data_output = (6 << 4)
+F_LD_digital_lock_detect = (1 << 4)
+F_LD_open_drain = (5 << 4)
+F_LD_high = (3 << 4)
+F_LD_low = (7 << 4)
+
+# F_default = F_LD_digital_lock_detect | F_phase_detector_polarity
+F_default = F_LD_open_drain | F_phase_detector_polarity
+
+#
+# 4 control pins:
+# CE always high
+# LE load enable. When LE goes high, data stored in the shift register
+# is loaded into one of the three registers
+# CLK data is clocked in on the rising edge
+# DATA single data bit. Entered MSB first
+
+DB_CLK = (1 << 0)
+DB_DATA = (1 << 1)
+DB_LE = (1 << 2)
+DB_CE = (1 << 3)
+
+class lmx2306 (object):
+ '''Control the National LMX2306 PLL'''
+ __slots__ = ['pp', 'shadow', 'fosc', 'r', 'step_size', 'verbose']
+ def __init__ (self, fosc, step_size, which_pp = 0):
+ '''FOSC is the frequency of the reference oscillator,
+ STEP_SIZE is the step between valid frequencies,
+ WHICH_PP specifies which parallel port to use
+ '''
+ self.pp = gr.make_ppio (which_pp)
+ self.shadow = DB_CE
+ self.pp.lock ()
+ self.pp.write_data (self.shadow)
+ self.pp.unlock ()
+ self.verbose = False
+ self._set_fosc (fosc)
+ self._set_step (step_size)
+
+
+ def program (self, r, a, b):
+ if self.verbose:
+ print "lmx2306: r = %d a = %d b = %d" % (r, a, b)
+ self.pp.lock ()
+ self._write_word (F_REG | F_default | F_counter_reset)
+ self._write_word (R_REG | ((r & 0x3fff) << 2))
+ self._write_word (AB_REG | ((a & 0x1f) << 2) | ((b & 0x1fff) << 7))
+ self._write_word (F_REG | F_default)
+ self.pp.unlock ()
+
+ def set_freq (self, freq):
+ '''Set the PLL frequency to FREQ
+
+ Return the actual freq value set. It will be rounded down to a
+ multiple of step_size
+ '''
+ divisor = int (freq / self.step_size)
+ actual = divisor * self.step_size
+ (a, b) = self._compute_ab (divisor)
+ self.program (self.r, a, b)
+ return actual
+
+ # ----------------------------------------------------------------
+
+ def _set_fosc (self, ref_oscillator_freq):
+ self.fosc = ref_oscillator_freq
+
+ def _set_step (self, step_size):
+ r = int (self.fosc / step_size)
+ if r * step_size != self.fosc:
+ raise ValueError, "step_size is not a factor of self.fosc"
+ if r < 3 or r > 16383:
+ raise ValueError, "r is out of range"
+ self.r = r
+ self.step_size = step_size
+
+ def _compute_ab (self, divisor):
+ b = divisor / 8
+ a = divisor - (b * 8)
+ if b < 3 or b > 8191 or a > b:
+ raise ValueError, "Invalid divisor"
+ return (a, b)
+
+ def _write_word (self, w):
+ for i in range(21):
+ if w & (1 << 20):
+ self._set_DATA_1 ()
+ else:
+ self._set_DATA_0 ()
+ w = (w << 1) & 0x0ffffff
+ self._set_CLK_1 ()
+ self._set_CLK_0 ()
+ self._set_LE_1 ()
+ self._set_LE_0 ()
+
+ def _set_LE_0 (self):
+ self.shadow = self.shadow & ~DB_LE
+ self.pp.write_data (self.shadow)
+
+ def _set_LE_1 (self):
+ self.shadow = self.shadow | DB_LE
+ self.pp.write_data (self.shadow)
+
+ def _set_CLK_0 (self):
+ self.shadow = self.shadow & ~DB_CLK
+ self.pp.write_data (self.shadow)
+
+ def _set_CLK_1 (self):
+ self.shadow = self.shadow | DB_CLK
+ self.pp.write_data (self.shadow)
+
+ def _set_DATA_0 (self):
+ self.shadow = self.shadow & ~DB_DATA
+ self.pp.write_data (self.shadow)
+
+ def _set_DATA_1 (self):
+ self.shadow = self.shadow | DB_DATA
+ self.pp.write_data (self.shadow)
+
+if __name__ == '__main__':
+ parser = OptionParser (option_class=eng_option)
+ parser.add_option ("-o", "--fosc", type="eng_float", default=32e6,
+ help="set reference oscillator freq to FREQ", metavar="FREQ")
+ parser.add_option ("-s", "--step-size", type="eng_float", default=10e3,
+ help="set the frequency step size to STEP_SIZE")
+ parser.add_option ("-f", "--freq", type="eng_float", default=430e6,
+ help="set VCO frequency to FREQ")
+ parser.add_option ("-v", "--verbose", action="store_true", default=False)
+ (options, args) = parser.parse_args ()
+
+ if options.verbose:
+ print "fosc = %s step = %s fvco = %s" % (
+ eng_notation.num_to_str (options.fosc),
+ eng_notation.num_to_str (options.step_size),
+ eng_notation.num_to_str (options.freq))
+
+ lmx = lmx2306 (options.fosc, options.step_size)
+ lmx.verbose = options.verbose
+
+ actual = lmx.set_freq (options.freq)
+
+ if options.verbose:
+ print "fvco_actual = %s delta = %s" % (
+ eng_notation.num_to_str (actual),
+ eng_notation.num_to_str (options.freq - actual))
diff --git a/gnuradio-core/src/python/gnuradio/gruimpl/mathmisc.py b/gnuradio-core/src/python/gnuradio/gruimpl/mathmisc.py
new file mode 100644
index 0000000000..13e6de80e0
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/gruimpl/mathmisc.py
@@ -0,0 +1,33 @@
+#
+# Copyright 2005 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.
+#
+
+import math
+
+def gcd(a,b):
+ while b:
+ a,b = b, a % b
+ return a
+
+def lcm(a,b):
+ return a * b / gcd(a, b)
+
+def log2(x):
+ return math.log(x)/math.log(2)
diff --git a/gnuradio-core/src/python/gnuradio/gruimpl/os_read_exactly.py b/gnuradio-core/src/python/gnuradio/gruimpl/os_read_exactly.py
new file mode 100644
index 0000000000..afdfb514bd
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/gruimpl/os_read_exactly.py
@@ -0,0 +1,36 @@
+#
+# Copyright 2005 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.
+#
+
+import os
+
+def os_read_exactly(file_descriptor, nbytes):
+ """
+ Replacement for os.read that blocks until it reads exactly nbytes.
+
+ """
+ s = ''
+ while nbytes > 0:
+ sbuf = os.read(file_descriptor, nbytes)
+ if not(sbuf):
+ return ''
+ nbytes -= len(sbuf)
+ s = s + sbuf
+ return s
diff --git a/gnuradio-core/src/python/gnuradio/gruimpl/sdr_1000.py b/gnuradio-core/src/python/gnuradio/gruimpl/sdr_1000.py
new file mode 100644
index 0000000000..5de23b7206
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/gruimpl/sdr_1000.py
@@ -0,0 +1,84 @@
+#
+# Copyright 2003,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.
+#
+
+from gnuradio import gr
+
+class sdr_1000 (gr.sdr_1000_base):
+ "Control the DDS on the SDR-1000"
+ def __init__(self, pport = 0):
+ gr.sdr_1000_base.__init__(self, pport)
+ self.write_latch (3, 0x00, 0xC0) # Reset low, WRS/ low
+ self.write_reg (0x20, 0x40)
+
+ def write_reg(self, addr, data):
+ self.write_latch (3, addr & 0x3f, 0x3f)
+ self.write_latch (2, data, 0xff)
+ self.write_latch (3, 0x40, 0x40)
+ self.write_latch (3, 0x00, 0x40)
+
+ def set_freq(self, freq):
+ self.set_band (freq)
+ ftw = freq / 200e6;
+ for i in xrange(6):
+ word = int(ftw * 256)
+ ftw = ftw*256 - word
+ # print (('%d [%02x]') % (i, word))
+ self.write_reg (4+i, word)
+
+ def set_band (self, freq):
+ if freq <= 2.25e6:
+ band = 0
+ elif freq <= 5.5e6:
+ band = 1
+ elif freq <= 11e6:
+ band = 3 # due to wiring mistake on board
+ elif freq <= 22e6:
+ band = 2 # due to wiring mistake on board
+ elif freq <= 37.5e6:
+ band = 4
+ else:
+ band = 5
+
+ self.write_latch (1, 1 << band, 0x3f)
+
+ def set_bit (self, reg, bit, state):
+ val = 0x00
+ if state: val = 1<<bit
+ self.write_latch (reg, val, 1<<bit)
+
+ def set_tx (self, on = 1):
+ self.set_bit(1, 6, on)
+
+ def set_rx (self):
+ self.set_bit(1, 6, 0)
+
+ def set_gain (self, high):
+ self.set_bit(0, 7, high)
+
+ def set_mute (self, mute = 1):
+ self.set_bit(1, 7, mute)
+
+ def set_unmute (self):
+ self.set_bit(1, 7, 0)
+
+ def set_external_pin (self, pin, on = 1):
+ assert (pin < 8 and pin > 0), "Out of range 1..7"
+ self.set_bit(0, pin-1, on)
diff --git a/gnuradio-core/src/python/gnuradio/gruimpl/seq_with_cursor.py b/gnuradio-core/src/python/gnuradio/gruimpl/seq_with_cursor.py
new file mode 100644
index 0000000000..5616dea9d9
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/gruimpl/seq_with_cursor.py
@@ -0,0 +1,77 @@
+#
+# Copyright 2003,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.
+#
+
+# misc utilities
+
+import types
+import exceptions
+
+class seq_with_cursor (object):
+ __slots__ = [ 'items', 'index' ]
+
+ def __init__ (self, items, initial_index = None, initial_value = None):
+ assert len (items) > 0, "seq_with_cursor: len (items) == 0"
+ self.items = items
+ self.set_index (initial_index)
+ if initial_value is not None:
+ self.set_index_by_value(initial_value)
+
+ def set_index (self, initial_index):
+ if initial_index is None:
+ self.index = len (self.items) / 2
+ elif initial_index >= 0 and initial_index < len (self.items):
+ self.index = initial_index
+ else:
+ raise exceptions.ValueError
+
+ def set_index_by_value(self, v):
+ """
+ Set index to the smallest value such that items[index] >= v.
+ If there is no such item, set index to the maximum value.
+ """
+ self.set_index(0) # side effect!
+ cv = self.current()
+ more = True
+ while cv < v and more:
+ cv, more = self.next() # side effect!
+
+ def next (self):
+ new_index = self.index + 1
+ if new_index < len (self.items):
+ self.index = new_index
+ return self.items[new_index], True
+ else:
+ return self.items[self.index], False
+
+ def prev (self):
+ new_index = self.index - 1
+ if new_index >= 0:
+ self.index = new_index
+ return self.items[new_index], True
+ else:
+ return self.items[self.index], False
+
+ def current (self):
+ return self.items[self.index]
+
+ def get_seq (self):
+ return self.items[:] # copy of items
+
diff --git a/gnuradio-core/src/python/gnuradio/gruimpl/socket_stuff.py b/gnuradio-core/src/python/gnuradio/gruimpl/socket_stuff.py
new file mode 100644
index 0000000000..05be0d4322
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/gruimpl/socket_stuff.py
@@ -0,0 +1,56 @@
+#
+# Copyright 2005 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.
+#
+
+# random socket related stuff
+
+import socket
+import os
+import sys
+
+def tcp_connect_or_die(sock_addr):
+ """
+ @param sock_addr: (host, port) to connect to
+ @type sock_addr: tuple
+ @returns: socket or exits
+ """
+ s = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
+ try:
+ s.connect(sock_addr)
+ except socket.error, err:
+ sys.stderr.write('Failed to connect to %s: %s\n' %
+ (sock_addr, os.strerror (err.args[0]),))
+ sys.exit(1)
+ return s
+
+def udp_connect_or_die(sock_addr):
+ """
+ @param sock_addr: (host, port) to connect to
+ @type sock_addr: tuple
+ @returns: socket or exits
+ """
+ s = socket.socket (socket.AF_INET, socket.SOCK_DGRAM)
+ try:
+ s.connect(sock_addr)
+ except socket.error, err:
+ sys.stderr.write('Failed to connect to %s: %s\n' %
+ (sock_addr, os.strerror (err.args[0]),))
+ sys.exit(1)
+ return s