merged trondeau/digital-wip2 r4193:4730 into trunk - improves digital receiver and...
[debian/gnuradio] / gnuradio-core / src / python / gnuradio / blksimpl2 / 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, 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_pkts(gr.hier_block2):
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, 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 modulator: instance of modulator class (gr_block or hier_block)
47         @type modulator: complex baseband out
48         @param access_code: AKA sync vector
49         @type access_code: string of 1's and 0's between 1 and 64 long
50         @param msgq_limit: maximum number of messages in message queue
51         @type msgq_limit: int
52         @param pad_for_usrp: If true, packets are padded such that they end up a multiple of 128 samples
53         """
54
55         gr.hier_block2.__init__(self, "mod_pkts",
56                                 gr.io_signature(0,0,0), # Input signature
57                                 gr.io_signature(1,1,gr.sizeof_gr_complex)) # Output signature
58
59         self._modulator = modulator
60         self._pad_for_usrp = pad_for_usrp
61
62         if access_code is None:
63             access_code = packet_utils.default_access_code
64         if not packet_utils.is_1_0_string(access_code):
65             raise ValueError, "Invalid access_code %r. Must be string of 1's and 0's" % (access_code,)
66         self._access_code = access_code
67
68         # accepts messages from the outside world
69         self._pkt_input = gr.message_source(gr.sizeof_char, msgq_limit)
70         self.define_component("packet_source", self._pkt_input)
71         self.define_component("modulator", self._modulator)
72
73         self.connect("packet_source", 0, "modulator", 0)
74         self.connect("modulator", 0, "self", 0)
75
76     def send_pkt(self, payload='', eof=False):
77         """
78         Send the payload.
79
80         @param payload: data to send
81         @type payload: string
82         """
83         if eof:
84             msg = gr.message(1) # tell self._pkt_input we're not sending any more packets
85         else:
86             # print "original_payload =", string_to_hex_list(payload)
87             pkt = packet_utils.make_packet(payload,
88                                            self._modulator.samples_per_symbol(),
89                                            self._modulator.bits_per_symbol(),
90                                            self._access_code,
91                                            self._pad_for_usrp)
92             #print "pkt =", string_to_hex_list(pkt)
93             msg = gr.message_from_string(pkt)
94         self._pkt_input.msgq().insert_tail(msg)
95
96
97
98 class demod_pkts(gr.hier_block2):
99     """
100     Wrap an arbitrary digital demodulator in our packet handling framework.
101
102     The input is complex baseband.  When packets are demodulated, they are passed to the
103     app via the callback.
104     """
105
106     def __init__(self, demodulator, access_code=None, callback=None, threshold=-1):
107         """
108         Hierarchical block for demodulating and deframing packets.
109
110         The input is the complex modulated signal at baseband.
111         Demodulated packets are sent to the handler.
112
113         @param demodulator: instance of demodulator class (gr_block or hier_block)
114         @type demodulator: complex baseband in
115         @param access_code: AKA sync vector
116         @type access_code: string of 1's and 0's
117         @param callback:  function of two args: ok, payload
118         @type callback: ok: bool; payload: string
119         @param threshold: detect access_code with up to threshold bits wrong (-1 -> use default)
120         @type threshold: int
121         """
122
123         gr.hier_block2.__init__(self, "demod_pkts",
124                                 gr.io_signature(1,1,gr.sizeof_gr_complex), # Input signature
125                                 gr.io_signature(0,0,0)) # Output signature
126                                 
127         self._demodulator = demodulator
128         if access_code is None:
129             access_code = packet_utils.default_access_code
130         if not packet_utils.is_1_0_string(access_code):
131             raise ValueError, "Invalid access_code %r. Must be string of 1's and 0's" % (access_code,)
132         self._access_code = access_code
133
134         if threshold == -1:
135             threshold = 12              # FIXME raise exception
136
137         self._rcvd_pktq = gr.msg_queue()          # holds packets from the PHY
138
139         self.define_component("demodulator", self._demodulator)
140         self.define_component("correlator", gr.correlate_access_code_bb(access_code, threshold))
141         self.define_component("framer_sink", gr.framer_sink_1(self._rcvd_pktq))
142
143         self.connect("self", 0, "demodulator",0)
144         self.connect("demodulator", 0, "correlator", 0)
145         self.connect("correlator", 0, "framer_sink", 0)
146
147         self._watcher = _queue_watcher_thread(self._rcvd_pktq, callback)
148
149
150 class _queue_watcher_thread(_threading.Thread):
151     def __init__(self, rcvd_pktq, callback):
152         _threading.Thread.__init__(self)
153         self.setDaemon(1)
154         self.rcvd_pktq = rcvd_pktq
155         self.callback = callback
156         self.keep_running = True
157         self.start()
158
159
160     def run(self):
161         while self.keep_running:
162             msg = self.rcvd_pktq.delete_head()
163             ok, payload = packet_utils.unmake_packet(msg.to_string())
164             if self.callback:
165                 self.callback(ok, payload)