diff options
author | jcorgan <jcorgan@221aa14e-8319-0410-a670-987f0aec2ac5> | 2006-08-03 04:51:51 +0000 |
---|---|---|
committer | jcorgan <jcorgan@221aa14e-8319-0410-a670-987f0aec2ac5> | 2006-08-03 04:51:51 +0000 |
commit | 5d69a524f81f234b3fbc41d49ba18d6f6886baba (patch) | |
tree | b71312bf7f1e8d10fef0f3ac6f28784065e73e72 /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')
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 |