Merged r4518:5130 from developer branch n4hy/ofdm into trunk, passes distcheck.
[debian/gnuradio] / gnuradio-core / src / python / gnuradio / blksimpl / ofdm_pkt.py
1 #
2 # Copyright 2005,2006 Free Software Foundation, Inc.
3
4 # This file is part of GNU Radio
5
6 # GNU Radio is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2, or (at your option)
9 # any later version.
10
11 # GNU Radio is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15
16 # You should have received a copy of the GNU General Public License
17 # along with GNU Radio; see the file COPYING.  If not, write to
18 # the Free Software Foundation, Inc., 51 Franklin Street,
19 # Boston, MA 02110-1301, USA.
20
21
22 from math import pi
23 import Numeric
24
25 from gnuradio import gr, ofdm_packet_utils
26 import gnuradio.gr.gr_threading as _threading
27
28
29 # /////////////////////////////////////////////////////////////////////////////
30 #                   mod/demod with packets as i/o
31 # /////////////////////////////////////////////////////////////////////////////
32
33 class mod_ofdm_pkts(gr.hier_block):
34     """
35     Wrap an arbitrary digital modulator in our packet handling framework.
36
37     Send packets by calling send_pkt
38     """
39     def __init__(self, fg, modulator, access_code=None, msgq_limit=2, pad_for_usrp=True):
40         """
41         Hierarchical block for sending packets
42
43         Packets to be sent are enqueued by calling send_pkt.
44         The output is the complex modulated signal at baseband.
45
46         @param fg: flow graph
47         @type fg: flow graph
48         @param modulator: instance of modulator class (gr_block or hier_block)
49         @type modulator: complex baseband out
50         @param access_code: AKA sync vector
51         @type access_code: string of 1's and 0's between 1 and 64 long
52         @param msgq_limit: maximum number of messages in message queue
53         @type msgq_limit: int
54         @param pad_for_usrp: If true, packets are padded such that they end up a multiple of 128 samples
55
56         See modulators for remaining parameters
57         """
58         self._modulator = modulator
59         self._pad_for_usrp = pad_for_usrp
60
61         if access_code is None:
62             access_code = ofdm_packet_utils.default_access_code
63         if not ofdm_packet_utils.is_1_0_string(access_code):
64             raise ValueError, "Invalid access_code %r. Must be string of 1's and 0's" % (access_code,)
65         self._access_code = access_code
66
67         # accepts messages from the outside world
68         self._pkt_input = gr.message_vector_source(self._modulator.mtu(), msgq_limit)
69         fg.connect(self._pkt_input, self._modulator)
70         gr.hier_block.__init__(self, fg, None, self._modulator)
71
72     def send_pkt(self, payload='', eof=False):
73         """
74         Send the payload.
75
76         @param payload: data to send
77         @type payload: string
78         """
79         if eof:
80             msg = gr.message(1) # tell self._pkt_input we're not sending any more packets
81         else:
82             # print "original_payload =", string_to_hex_list(payload)
83             pkt = ofdm_packet_utils.make_packet(payload,
84                                                 self._modulator.samples_per_symbol(),
85                                                 self._modulator.bits_per_symbol(),
86                                                 self._access_code,
87                                                 self._pad_for_usrp)
88             #print "pkt =", string_to_hex_list(pkt)
89             msg = gr.message_from_string(pkt)
90         self._pkt_input.msgq().insert_tail(msg)
91
92
93
94 class demod_ofdm_pkts(gr.hier_block):
95     """
96     Wrap an arbitrary digital demodulator in our packet handling framework.
97
98     The input is complex baseband.  When packets are demodulated, they are passed to the
99     app via the callback.
100     """
101
102     def __init__(self, fg, demodulator, access_code=None, callback=None, threshold=-1):
103         """
104         Hierarchical block for demodulating and deframing packets.
105
106         The input is the complex modulated signal at baseband.
107         Demodulated packets are sent to the handler.
108
109         @param fg: flow graph
110         @type fg: flow graph
111         @param demodulator: instance of demodulator class (gr_block or hier_block)
112         @type demodulator: complex baseband in
113         @param access_code: AKA sync vector
114         @type access_code: string of 1's and 0's
115         @param callback:  function of two args: ok, payload
116         @type callback: ok: bool; payload: string
117         @param threshold: detect access_code with up to threshold bits wrong (-1 -> use default)
118         @type threshold: int
119         """
120
121         self._demodulator = demodulator
122         if access_code is None:
123             access_code = ofdm_packet_utils.default_access_code
124         if not ofdm_packet_utils.is_1_0_string(access_code):
125             raise ValueError, "Invalid access_code %r. Must be string of 1's and 0's" % (access_code,)
126         self._access_code = access_code
127
128         if threshold == -1:
129             threshold = 12              # FIXME raise exception
130
131         self._rcvd_pktq = gr.msg_queue()          # holds packets from the PHY
132         self.bytes_to_bits = gr.packed_to_unpacked_bb(1, gr.GR_MSB_FIRST)
133         self.correlator = gr.correlate_access_code_bb(access_code, threshold)
134
135         self.framer_sink = gr.framer_sink_1(self._rcvd_pktq)
136         fg.connect(self._demodulator, self.bytes_to_bits, self.correlator, self.framer_sink)
137
138         if 0:
139             fg.connect(self.bytes_to_bits, gr.file_sink(gr.sizeof_char, "received_bits.out"))
140         
141         gr.hier_block.__init__(self, fg, self._demodulator, None)
142         self._watcher = _queue_watcher_thread(self._rcvd_pktq, callback)
143
144
145 class _queue_watcher_thread(_threading.Thread):
146     def __init__(self, rcvd_pktq, callback):
147         _threading.Thread.__init__(self)
148         self.setDaemon(1)
149         self.rcvd_pktq = rcvd_pktq
150         self.callback = callback
151         self.keep_running = True
152         self.start()
153
154
155     def run(self):
156         while self.keep_running:
157             msg = self.rcvd_pktq.delete_head()
158             ok, payload = ofdm_packet_utils.unmake_packet(msg.to_string())
159             if self.callback:
160                 self.callback(ok, payload)