]> git.gag.com Git - debian/gnuradio/blob - grc/src/grc_gnuradio/blks2/packet.py
Added OFDM Mod and Demod to GRC (cough cough... kludge).
[debian/gnuradio] / grc / src / grc_gnuradio / blks2 / packet.py
1 # Copyright 2008, 2009 Free Software Foundation, Inc.
2 #
3 # This file is part of GNU Radio
4 #
5 # GNU Radio is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3, or (at your option)
8 # any later version.
9 #
10 # GNU Radio is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with GNU Radio; see the file COPYING.  If not, write to
17 # the Free Software Foundation, Inc., 51 Franklin Street,
18 # Boston, MA 02110-1301, USA.
19 #
20
21 from gnuradio import gr, packet_utils
22 import gnuradio.gr.gr_threading as _threading
23
24 ##payload length in bytes
25 DEFAULT_PAYLOAD_LEN = 512
26
27 ##how many messages in a queue
28 DEFAULT_MSGQ_LIMIT = 2
29
30 ##threshold for unmaking packets
31 DEFAULT_THRESHOLD = 12
32
33 ##################################################
34 ## Options Class for OFDM
35 ##################################################
36 class options(object):
37         def __init__(self, **kwargs):
38                 for key, value in kwargs.iteritems(): setattr(self, key, value)
39
40 ##################################################
41 ## Packet Encoder
42 ##################################################
43 class _packet_encoder_thread(_threading.Thread):
44
45         def __init__(self, msgq, payload_length, send):
46                 self._msgq = msgq
47                 self._payload_length = payload_length
48                 self._send = send
49                 _threading.Thread.__init__(self)
50                 self.setDaemon(1)
51                 self.keep_running = True
52                 self.start()
53
54         def run(self):
55                 sample = '' #residual sample
56                 while self.keep_running:
57                         msg = self._msgq.delete_head() #blocking read of message queue
58                         sample = sample + msg.to_string() #get the body of the msg as a string
59                         while len(sample) >= self._payload_length:
60                                 payload = sample[:self._payload_length]
61                                 sample = sample[self._payload_length:]
62                                 self._send(payload)
63
64 class packet_encoder(gr.hier_block2):
65         """
66         Hierarchical block for wrapping packet-based modulators.
67         """
68
69         def __init__(self, samples_per_symbol, bits_per_symbol, access_code='', pad_for_usrp=True):
70                 """
71                 packet_mod constructor.
72                 @param samples_per_symbol number of samples per symbol
73                 @param bits_per_symbol number of bits per symbol
74                 @param access_code AKA sync vector
75                 @param pad_for_usrp If true, packets are padded such that they end up a multiple of 128 samples
76                 @param payload_length number of bytes in a data-stream slice
77                 """
78                 #setup parameters
79                 self._samples_per_symbol = samples_per_symbol
80                 self._bits_per_symbol = bits_per_symbol
81                 self._pad_for_usrp = pad_for_usrp
82                 if not access_code: #get access code
83                         access_code = packet_utils.default_access_code
84                 if not packet_utils.is_1_0_string(access_code):
85                         raise ValueError, "Invalid access_code %r. Must be string of 1's and 0's" % (access_code,)
86                 self._access_code = access_code
87                 self._pad_for_usrp = pad_for_usrp
88                 #create blocks
89                 msg_source = gr.message_source(gr.sizeof_char, DEFAULT_MSGQ_LIMIT)
90                 self._msgq_out = msg_source.msgq()
91                 #initialize hier2
92                 gr.hier_block2.__init__(
93                         self,
94                         "packet_encoder",
95                         gr.io_signature(0, 0, 0), # Input signature
96                         gr.io_signature(1, 1, gr.sizeof_char) # Output signature
97                 )
98                 #connect
99                 self.connect(msg_source, self)
100
101         def send_pkt(self, payload):
102                 """
103                 Wrap the payload in a packet and push onto the message queue.
104                 @param payload string, data to send
105                 """
106                 packet = packet_utils.make_packet(
107                         payload,
108                         self._samples_per_symbol,
109                         self._bits_per_symbol,
110                         self._access_code,
111                         self._pad_for_usrp
112                 )
113                 msg = gr.message_from_string(packet)
114                 self._msgq_out.insert_tail(msg)
115
116 ##################################################
117 ## Packet Decoder
118 ##################################################
119 class _packet_decoder_thread(_threading.Thread):
120
121         def __init__(self, msgq, callback):
122                 _threading.Thread.__init__(self)
123                 self.setDaemon(1)
124                 self._msgq = msgq
125                 self.callback = callback
126                 self.keep_running = True
127                 self.start()
128
129         def run(self):
130                 while self.keep_running:
131                         msg = self._msgq.delete_head()
132                         ok, payload = packet_utils.unmake_packet(msg.to_string(), int(msg.arg1()))
133                         if self.callback:
134                                 self.callback(ok, payload)
135
136 class packet_decoder(gr.hier_block2):
137         """
138         Hierarchical block for wrapping packet-based demodulators.
139         """
140
141         def __init__(self, access_code='', threshold=-1, callback=None):
142                 """
143                 packet_demod constructor.
144                 @param access_code AKA sync vector
145                 @param threshold detect access_code with up to threshold bits wrong (0 -> use default)
146                 @param callback a function of args: ok, payload
147                 """
148                 #access code
149                 if not access_code: #get access code
150                         access_code = packet_utils.default_access_code
151                 if not packet_utils.is_1_0_string(access_code):
152                         raise ValueError, "Invalid access_code %r. Must be string of 1's and 0's" % (access_code,)
153                 self._access_code = access_code
154                 #threshold
155                 if threshold < 0: threshold = DEFAULT_THRESHOLD
156                 self._threshold = threshold
157                 #blocks
158                 msgq = gr.msg_queue(DEFAULT_MSGQ_LIMIT) #holds packets from the PHY
159                 correlator = gr.correlate_access_code_bb(self._access_code, self._threshold)
160                 framer_sink = gr.framer_sink_1(msgq)
161                 #initialize hier2
162                 gr.hier_block2.__init__(
163                         self,
164                         "packet_decoder",
165                         gr.io_signature(1, 1, gr.sizeof_char), # Input signature
166                         gr.io_signature(0, 0, 0) # Output signature
167                 )
168                 #connect
169                 self.connect(self, correlator, framer_sink)
170                 #start thread
171                 _packet_decoder_thread(msgq, callback)
172
173 ##################################################
174 ## Packet Mod for OFDM Mod and Packet Encoder
175 ##################################################
176 class packet_mod_base(gr.hier_block2):
177         """
178         Hierarchical block for wrapping packet source block.
179         """
180
181         def __init__(self, packet_source=None, payload_length=0):
182                 if not payload_length: #get payload length
183                         payload_length = DEFAULT_PAYLOAD_LEN
184                 if payload_length%self._item_size_in != 0:      #verify that packet length is a multiple of the stream size
185                         raise ValueError, 'The payload length: "%d" is not a mutiple of the stream size: "%d".'%(payload_length, self._item_size_in)
186                 #initialize hier2
187                 gr.hier_block2.__init__(
188                         self,
189                         "ofdm_mod",
190                         gr.io_signature(1, 1, self._item_size_in), # Input signature
191                         gr.io_signature(1, 1, packet_source._hb.output_signature().sizeof_stream_item(0)) # Output signature
192                 )
193                 #create blocks
194                 msgq = gr.msg_queue(DEFAULT_MSGQ_LIMIT)
195                 msg_sink = gr.message_sink(self._item_size_in, msgq, False) #False -> blocking
196                 copy = gr.kludge_copy(packet_source._hb.output_signature().sizeof_stream_item(0))
197                 #connect
198                 self.connect(self, msg_sink)
199                 self.connect(packet_source, copy, self)
200                 #start thread
201                 _packet_encoder_thread(msgq, payload_length, packet_source.send_pkt)
202
203 class packet_mod_b(packet_mod_base): _item_size_in = gr.sizeof_char
204 class packet_mod_s(packet_mod_base): _item_size_in = gr.sizeof_short
205 class packet_mod_i(packet_mod_base): _item_size_in = gr.sizeof_int
206 class packet_mod_f(packet_mod_base): _item_size_in = gr.sizeof_float
207 class packet_mod_c(packet_mod_base): _item_size_in = gr.sizeof_gr_complex
208
209 ##################################################
210 ## Packet Demod for OFDM Demod and Packet Decoder
211 ##################################################
212 class packet_demod_base(gr.hier_block2):
213         """
214         Hierarchical block for wrapping packet sink block.
215         """
216
217         def __init__(self, packet_sink=None):
218                 #initialize hier2
219                 gr.hier_block2.__init__(
220                         self,
221                         "ofdm_mod",
222                         gr.io_signature(1, 1, packet_sink._hb.input_signature().sizeof_stream_item(0)), # Input signature
223                         gr.io_signature(1, 1, self._item_size_out) # Output signature
224                 )
225                 #create blocks
226                 msg_source = gr.message_source(self._item_size_out, DEFAULT_MSGQ_LIMIT)
227                 self._msgq_out = msg_source.msgq()
228                 copy = gr.kludge_copy(packet_sink._hb.input_signature().sizeof_stream_item(0))
229                 #connect
230                 self.connect(self, copy, packet_sink)
231                 self.connect(msg_source, self)
232                 if packet_sink._hb.output_signature().sizeof_stream_item(0):
233                         self.connect(packet_sink, gr.null_sink(packet_sink._hb.output_signature().sizeof_stream_item(0)))
234
235         def recv_pkt(self, ok, payload):
236                 msg = gr.message_from_string(payload, 0, self._item_size_out, len(payload)/self._item_size_out)
237                 if ok: self._msgq_out.insert_tail(msg)
238
239 class packet_demod_b(packet_demod_base): _item_size_out = gr.sizeof_char
240 class packet_demod_s(packet_demod_base): _item_size_out = gr.sizeof_short
241 class packet_demod_i(packet_demod_base): _item_size_out = gr.sizeof_int
242 class packet_demod_f(packet_demod_base): _item_size_out = gr.sizeof_float
243 class packet_demod_c(packet_demod_base): _item_size_out = gr.sizeof_gr_complex