diff options
Diffstat (limited to 'gnuradio-runtime/python/gnuradio/gru')
-rw-r--r-- | gnuradio-runtime/python/gnuradio/gru/CMakeLists.txt | 36 | ||||
-rw-r--r-- | gnuradio-runtime/python/gnuradio/gru/__init__.py | 13 | ||||
-rw-r--r-- | gnuradio-runtime/python/gnuradio/gru/daemon.py | 102 | ||||
-rw-r--r-- | gnuradio-runtime/python/gnuradio/gru/freqz.py | 344 | ||||
-rwxr-xr-x | gnuradio-runtime/python/gnuradio/gru/gnuplot_freqz.py | 102 | ||||
-rw-r--r-- | gnuradio-runtime/python/gnuradio/gru/hexint.py | 44 | ||||
-rw-r--r-- | gnuradio-runtime/python/gnuradio/gru/listmisc.py | 29 | ||||
-rw-r--r-- | gnuradio-runtime/python/gnuradio/gru/mathmisc.py | 33 | ||||
-rw-r--r-- | gnuradio-runtime/python/gnuradio/gru/msgq_runner.py | 82 | ||||
-rw-r--r-- | gnuradio-runtime/python/gnuradio/gru/os_read_exactly.py | 36 | ||||
-rw-r--r-- | gnuradio-runtime/python/gnuradio/gru/seq_with_cursor.py | 77 | ||||
-rw-r--r-- | gnuradio-runtime/python/gnuradio/gru/socket_stuff.py | 62 |
12 files changed, 960 insertions, 0 deletions
diff --git a/gnuradio-runtime/python/gnuradio/gru/CMakeLists.txt b/gnuradio-runtime/python/gnuradio/gru/CMakeLists.txt new file mode 100644 index 0000000000..c147981472 --- /dev/null +++ b/gnuradio-runtime/python/gnuradio/gru/CMakeLists.txt @@ -0,0 +1,36 @@ +# Copyright 2010-2011 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. + +include(GrPython) + +GR_PYTHON_INSTALL(FILES + __init__.py + freqz.py + gnuplot_freqz.py + hexint.py + listmisc.py + mathmisc.py + msgq_runner.py + os_read_exactly.py + seq_with_cursor.py + socket_stuff.py + daemon.py + DESTINATION ${GR_PYTHON_DIR}/gnuradio/gru + COMPONENT "core_python" +) diff --git a/gnuradio-runtime/python/gnuradio/gru/__init__.py b/gnuradio-runtime/python/gnuradio/gru/__init__.py new file mode 100644 index 0000000000..4e41d03a74 --- /dev/null +++ b/gnuradio-runtime/python/gnuradio/gru/__init__.py @@ -0,0 +1,13 @@ +# make this a package + +# Import gru stuff +from daemon import * +from freqz import * +from gnuplot_freqz import * +from hexint import * +from listmisc import * +from mathmisc import * +from msgq_runner import * +from os_read_exactly import * +from seq_with_cursor import * +from socket_stuff import * diff --git a/gnuradio-runtime/python/gnuradio/gru/daemon.py b/gnuradio-runtime/python/gnuradio/gru/daemon.py new file mode 100644 index 0000000000..e04702152d --- /dev/null +++ b/gnuradio-runtime/python/gnuradio/gru/daemon.py @@ -0,0 +1,102 @@ +# +# Copyright 2008 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. +# +import os, sys, signal + +# Turn application into a background daemon process. +# +# When this function returns: +# +# 1) The calling process is disconnected from its controlling terminal +# and will not exit when the controlling session exits +# 2) If a pidfile name is provided, it is created and the new pid is +# written into it. +# 3) If a logfile name is provided, it is opened and stdout/stderr are +# redirected to it. +# 4) The process current working directory is changed to '/' to avoid +# pinning any filesystem mounts. +# 5) The process umask is set to 0111. +# +# The return value is the new pid. +# +# To create GNU Radio applications that operate as daemons, add a call to this +# function after all initialization but just before calling gr.top_block.run() +# or .start(). +# +# Daemonized GNU Radio applications may be stopped by sending them a +# SIGINT, SIGKILL, or SIGTERM, e.g., using 'kill pid' from the command line. +# +# If your application uses gr.top_block.run(), the flowgraph will be stopped +# and the function will return. You should allow your daemon program to exit +# at this point. +# +# If your application uses gr.top_block.start(), you are responsible for hooking +# the Python signal handler (see 'signal' module) and calling gr.top_block.stop() +# on your top block, and otherwise causing your daemon process to exit. +# + +def daemonize(pidfile=None, logfile=None): + # fork() into background + try: + pid = os.fork() + except OSError, e: + raise Exception, "%s [%d]" % (e.strerror, e.errno) + + if pid == 0: # First child of first fork() + # Become session leader of new session + os.setsid() + + # fork() into background again + try: + pid = os.fork() + except OSError, e: + raise Exception, "%s [%d]" % (e.strerror, e.errno) + + if pid != 0: + os._exit(0) # Second child of second fork() + + else: # Second child of first fork() + os._exit(0) + + os.umask(0111) + + # Write pid + pid = os.getpid() + if pidfile is not None: + open(pidfile, 'w').write('%d\n'%pid) + + # Redirect streams + if logfile is not None: + lf = open(logfile, 'a+') + sys.stdout = lf + sys.stderr = lf + + # Prevent pinning any filesystem mounts + os.chdir('/') + + # Tell caller what pid to send future signals to + return pid + +if __name__ == "__main__": + import time + daemonize() + print "Hello, world, from daemon process." + time.sleep(20) + print "Goodbye, world, from daemon process." diff --git a/gnuradio-runtime/python/gnuradio/gru/freqz.py b/gnuradio-runtime/python/gnuradio/gru/freqz.py new file mode 100644 index 0000000000..60dca64a58 --- /dev/null +++ b/gnuradio-runtime/python/gnuradio/gru/freqz.py @@ -0,0 +1,344 @@ +#!/usr/bin/env python +# +# Copyright 2005,2007 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. +# + +# 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 numpy +from numpy import * +Num=numpy + +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 = numpy.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 = numpy.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 = numpy.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 = numpy.zeros(key-self.order,self.coeffs.typecode()) + self.__dict__['coeffs'] = numpy.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-runtime/python/gnuradio/gru/gnuplot_freqz.py b/gnuradio-runtime/python/gnuradio/gru/gnuplot_freqz.py new file mode 100755 index 0000000000..dd483e4277 --- /dev/null +++ b/gnuradio-runtime/python/gnuradio/gru/gnuplot_freqz.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python +# +# Copyright 2005,2007 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. +# + +__all__ = ['gnuplot_freqz'] + +import tempfile +import os +import math +import numpy + +from gnuradio import gr +from gnuradio.gru.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 * numpy.log10 (numpy.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 = firdes.low_pass(1, sample_rate, 200000, 100000, firdes.WIN_HAMMING) + taps = (0.0007329441141337156, 0.0007755281985737383, 0.0005323155201040208, + -7.679847761841656e-19, -0.0007277769618667662, -0.001415981911122799, + -0.0017135187517851591, -0.001282231998629868, 1.61239866282397e-18, + 0.0018589380197227001, 0.0035909228026866913, 0.004260237794369459, + 0.00310456077568233, -3.0331308923229716e-18, -0.004244099836796522, + -0.007970594801008701, -0.009214458055794239, -0.006562007591128349, + 4.714311174044374e-18, 0.008654761128127575, 0.01605774275958538, + 0.01841980405151844, 0.013079923577606678, -6.2821650235090215e-18, + -0.017465557903051376, -0.032989680767059326, -0.03894065320491791, + -0.028868533670902252, 7.388111706347014e-18, 0.04517475143074989, + 0.09890196472406387, 0.14991308748722076, 0.18646684288978577, + 0.19974154233932495, 0.18646684288978577, 0.14991308748722076, + 0.09890196472406387, 0.04517475143074989, 7.388111706347014e-18, + -0.028868533670902252, -0.03894065320491791, -0.032989680767059326, + -0.017465557903051376, -6.2821650235090215e-18, 0.013079923577606678, + 0.01841980405151844, 0.01605774275958538, 0.008654761128127575, + 4.714311174044374e-18, -0.006562007591128349, -0.009214458055794239, + -0.007970594801008701, -0.004244099836796522, -3.0331308923229716e-18, + 0.00310456077568233, 0.004260237794369459, 0.0035909228026866913, + 0.0018589380197227001, 1.61239866282397e-18, -0.001282231998629868, + -0.0017135187517851591, -0.001415981911122799, -0.0007277769618667662, + -7.679847761841656e-19, 0.0005323155201040208, 0.0007755281985737383, + 0.0007329441141337156) + + # 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-runtime/python/gnuradio/gru/hexint.py b/gnuradio-runtime/python/gnuradio/gru/hexint.py new file mode 100644 index 0000000000..0fb5ecde04 --- /dev/null +++ b/gnuradio-runtime/python/gnuradio/gru/hexint.py @@ -0,0 +1,44 @@ +# +# 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 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. +# + +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 + +def hexshort(mask): + """ + Convert unsigned masks into signed shorts. + + This allows us to use hex constants like 0x8000 when talking to + our hardware and not get screwed by them getting treated as python + longs. + """ + if mask >= 2**15: + return int(mask-2**16) + return mask diff --git a/gnuradio-runtime/python/gnuradio/gru/listmisc.py b/gnuradio-runtime/python/gnuradio/gru/listmisc.py new file mode 100644 index 0000000000..9e70eb863c --- /dev/null +++ b/gnuradio-runtime/python/gnuradio/gru/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 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. +# + +def list_reverse(x): + """ + Return a copy of x that is reverse order. + """ + r = list(x) + r.reverse() + return r + diff --git a/gnuradio-runtime/python/gnuradio/gru/mathmisc.py b/gnuradio-runtime/python/gnuradio/gru/mathmisc.py new file mode 100644 index 0000000000..7e6f23a346 --- /dev/null +++ b/gnuradio-runtime/python/gnuradio/gru/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 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. +# + +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-runtime/python/gnuradio/gru/msgq_runner.py b/gnuradio-runtime/python/gnuradio/gru/msgq_runner.py new file mode 100644 index 0000000000..767a74a717 --- /dev/null +++ b/gnuradio-runtime/python/gnuradio/gru/msgq_runner.py @@ -0,0 +1,82 @@ +# +# Copyright 2009 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. +# + +""" +Convenience class for dequeuing messages from a gr.msg_queue and +invoking a callback. + +Creates a Python thread that does a blocking read on the supplied +gr.msg_queue, then invokes callback each time a msg is received. + +If the msg type is not 0, then it is treated as a signal to exit +its loop. + +If the callback raises an exception, and the runner was created +with 'exit_on_error' equal to True, then the runner will store the +exception and exit its loop, otherwise the exception is ignored. + +To get the exception that the callback raised, if any, call +exit_error() on the object. + +To manually stop the runner, call stop() on the object. + +To determine if the runner has exited, call exited() on the object. +""" + +from gnuradio import gr +import gnuradio.gr.gr_threading as _threading + +class msgq_runner(_threading.Thread): + + def __init__(self, msgq, callback, exit_on_error=False): + _threading.Thread.__init__(self) + + self._msgq = msgq + self._callback = callback + self._exit_on_error = exit_on_error + self._done = False + self._exited = False + self._exit_error = None + self.setDaemon(1) + self.start() + + def run(self): + while not self._done: + msg = self._msgq.delete_head() + if msg.type() != 0: + self.stop() + else: + try: + self._callback(msg) + except Exception, e: + if self._exit_on_error: + self._exit_error = e + self.stop() + self._exited = True + + def stop(self): + self._done = True + + def exited(self): + return self._exited + + def exit_error(self): + return self._exit_error diff --git a/gnuradio-runtime/python/gnuradio/gru/os_read_exactly.py b/gnuradio-runtime/python/gnuradio/gru/os_read_exactly.py new file mode 100644 index 0000000000..40b053770e --- /dev/null +++ b/gnuradio-runtime/python/gnuradio/gru/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 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. +# + +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-runtime/python/gnuradio/gru/seq_with_cursor.py b/gnuradio-runtime/python/gnuradio/gru/seq_with_cursor.py new file mode 100644 index 0000000000..def3299b69 --- /dev/null +++ b/gnuradio-runtime/python/gnuradio/gru/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 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. +# + +# 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-runtime/python/gnuradio/gru/socket_stuff.py b/gnuradio-runtime/python/gnuradio/gru/socket_stuff.py new file mode 100644 index 0000000000..489b6ab255 --- /dev/null +++ b/gnuradio-runtime/python/gnuradio/gru/socket_stuff.py @@ -0,0 +1,62 @@ +# +# 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 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. +# + +# random socket related stuff + +import socket +import os +import sys + +def tcp_connect_or_die(sock_addr): + """ + + Args: + sock_addr: (host, port) to connect to (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): + """ + + Args: + sock_addr: (host, port) to connect to (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 |