Generate more informative error message than recursion error
[debian/gnuradio] / gnuradio-core / src / python / gnuradio / packet_utils.py
index 7d4871473cbf9925aa8e5e9346152056af6eb4f7..1417c17fa5b1d731a70bd07571040b66b710d5ed 100644 (file)
@@ -1,11 +1,11 @@
 #
-# Copyright 2005,2006 Free Software Foundation, Inc.
+# Copyright 2005,2006,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 2, or (at your option)
+# 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,
@@ -20,7 +20,7 @@
 # 
 
 import struct
-import Numeric
+import numpy
 from gnuradio import gru
 
 
@@ -71,7 +71,8 @@ def conv_1_0_string_to_packed_binary_string(s):
 
 default_access_code = \
   conv_packed_binary_string_to_1_0_string('\xAC\xDD\xA4\xE2\xF2\x8C\x20\xFC')
-
+preamble = \
+  conv_packed_binary_string_to_1_0_string('\xA4\xF2')
 
 def is_1_0_string(s):
     if not isinstance(s, str):
@@ -85,28 +86,34 @@ def string_to_hex_list(s):
     return map(lambda x: hex(ord(x)), s)
 
 
-def whiten(s):
-    sa = Numeric.fromstring(s, Numeric.UnsignedInt8)
-    z = sa ^ random_mask_vec8[0:len(sa)]
+def whiten(s, o):
+    sa = numpy.fromstring(s, numpy.uint8)
+    z = sa ^ random_mask_vec8[o:len(sa)+o]
     return z.tostring()
 
-def dewhiten(s):
-    return whiten(s)        # self inverse
+def dewhiten(s, o):
+    return whiten(s, o)        # self inverse
 
 
-def make_header(payload_len):
-    return struct.pack('!HH', payload_len, payload_len)
+def make_header(payload_len, whitener_offset=0):
+    # Upper nibble is offset, lower 12 bits is len
+    val = ((whitener_offset & 0xf) << 12) | (payload_len & 0x0fff)
+    #print "offset =", whitener_offset, " len =", payload_len, " val=", val
+    return struct.pack('!HH', val, val)
 
-def make_packet(payload, spb, bits_per_baud, access_code=default_access_code, pad_for_usrp=True):
+def make_packet(payload, samples_per_symbol, bits_per_symbol,
+                access_code=default_access_code, pad_for_usrp=True,
+                whitener_offset=0, whitening=True):
     """
-    Build a packet, given access code and payload.
-
-    @param payload:       packet payload, len [0, 4096]
-    @param spb:           samples per baud (needed for padding calculation)
-    @type  spb:           int
-    @param bits_per_baud: (needed for padding calculation)
-    @type bits_per_baud:  int
-    @param access_code:   string of ascii 0's and 1's
+    Build a packet, given access code, payload, and whitener offset
+
+    @param payload:               packet payload, len [0, 4096]
+    @param samples_per_symbol:    samples per symbol (needed for padding calculation)
+    @type  samples_per_symbol:    int
+    @param bits_per_symbol:       (needed for padding calculation)
+    @type bits_per_symbol:        int
+    @param access_code:           string of ascii 0's and 1's
+    @param whitener_offset        offset into whitener string to use [0-16)
     
     Packet will have access code at the beginning, followed by length, payload
     and finally CRC-32.
@@ -114,7 +121,11 @@ def make_packet(payload, spb, bits_per_baud, access_code=default_access_code, pa
     if not is_1_0_string(access_code):
         raise ValueError, "access_code must be a string containing only 0's and 1's (%r)" % (access_code,)
 
+    if not whitener_offset >=0 and whitener_offset < 16:
+        raise ValueError, "whitener_offset must be between 0 and 15, inclusive (%i)" % (whitener_offset,)
+
     (packed_access_code, padded) = conv_1_0_string_to_packed_binary_string(access_code)
+    (packed_preamble, ignore) = conv_1_0_string_to_packed_binary_string(preamble)
     
     payload_with_crc = gru.gen_and_append_crc32(payload)
     #print "outbound crc =", string_to_hex_list(payload_with_crc[-4:])
@@ -124,14 +135,20 @@ def make_packet(payload, spb, bits_per_baud, access_code=default_access_code, pa
     if L > MAXLEN:
         raise ValueError, "len(payload) must be in [0, %d]" % (MAXLEN,)
 
-    pkt = ''.join((packed_access_code, make_header(L), whiten(payload_with_crc), '\x55'))
+    if whitening:
+        pkt = ''.join((packed_preamble, packed_access_code, make_header(L, whitener_offset),
+                       whiten(payload_with_crc, whitener_offset), '\x55'))
+    else:
+        pkt = ''.join((packed_preamble, packed_access_code, make_header(L, whitener_offset),
+                       (payload_with_crc), '\x55'))
+
     if pad_for_usrp:
-        pkt = pkt + (_npadding_bytes(len(pkt), spb, bits_per_baud) * '\x55')
+        pkt = pkt + (_npadding_bytes(len(pkt), samples_per_symbol, bits_per_symbol) * '\x55')
 
     #print "make_packet: len(pkt) =", len(pkt)
     return pkt
 
-def _npadding_bytes(pkt_byte_len, spb, bits_per_baud):
+def _npadding_bytes(pkt_byte_len, samples_per_symbol, bits_per_symbol):
     """
     Generate sufficient padding such that each packet ultimately ends
     up being a multiple of 512 bytes when sent across the USB.  We
@@ -140,26 +157,33 @@ def _npadding_bytes(pkt_byte_len, spb, bits_per_baud):
     is a multiple of 128 samples.
 
     @param ptk_byte_len: len in bytes of packet, not including padding.
-    @param spb: samples per baud == samples per bit (1 bit / baud with GMSK)
-    @type spb: int
+    @param samples_per_symbol: samples per bit (1 bit / symbolwidth GMSK)
+    @type samples_per_symbol: int
+    @param bits_per_symbol: bits per symbol (log2(modulation order))
+    @type bits_per_symbol: int
 
     @returns number of bytes of padding to append.
     """
     modulus = 128
-    byte_modulus = gru.lcm(modulus/8, spb) * bits_per_baud / spb
+    byte_modulus = gru.lcm(modulus/8, samples_per_symbol) * bits_per_symbol / samples_per_symbol
     r = pkt_byte_len % byte_modulus
     if r == 0:
         return 0
     return byte_modulus - r
     
 
-def unmake_packet(whitened_payload_with_crc):
+def unmake_packet(whitened_payload_with_crc, whitener_offset=0, dewhitening=True):
     """
     Return (ok, payload)
 
     @param whitened_payload_with_crc: string
     """
-    payload_with_crc = dewhiten(whitened_payload_with_crc)
+
+    if dewhitening:
+        payload_with_crc = dewhiten(whitened_payload_with_crc, whitener_offset)
+    else:
+        payload_with_crc = (whitened_payload_with_crc)
+
     ok, payload = gru.check_crc32(payload_with_crc)
 
     if 0:
@@ -429,5 +453,5 @@ random_mask_tuple = (
   199, 113, 146, 164, 109, 187, 109, 179, 109, 181, 237, 183,  13, 182, 133, 182, 
   227,  54, 201, 214, 214, 222, 222, 216,  88,  90, 186, 187,  51,  51, 255,  63 )
 
-random_mask_vec8 = Numeric.array(random_mask_tuple, Numeric.UnsignedInt8)
+random_mask_vec8 = numpy.array(random_mask_tuple, numpy.uint8)