1 # Copyright 2008 Free Software Foundation, Inc.
3 # This file is part of GNU Radio
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)
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.
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.
21 from gnuradio import gr, packet_utils
22 import gnuradio.gr.gr_threading as _threading
24 ##payload length in bytes
25 DEFAULT_PAYLOAD_LEN = 512
27 ##how many messages in a queue
28 DEFAULT_MSGQ_LIMIT = 2
30 ##threshold for unmaking packets
31 DEFAULT_THRESHOLD = 12
33 #######################################################################################
35 #######################################################################################
37 class _packet_encoder_thread(_threading.Thread):
39 def __init__(self, msgq, payload_length, send):
41 self._payload_length = payload_length
43 _threading.Thread.__init__(self)
45 self.keep_running = True
49 sample = '' #residual sample
50 while self.keep_running:
51 msg = self._msgq.delete_head() #blocking read of message queue
52 sample = sample + msg.to_string() #get the body of the msg as a string
53 while len(sample) >= self._payload_length:
54 payload = sample[0:self._payload_length]
55 sample = sample[self._payload_length:]
58 class packet_encoder(gr.hier_block2):
60 Hierarchical block for wrapping packet-based modulators.
63 def __init__(self, item_size_in, samples_per_symbol, bits_per_symbol, access_code='', pad_for_usrp=True, payload_length=-1):
65 packet_mod constructor.
66 @param item_size_in the size of the input data stream in bytes
67 @param samples_per_symbol number of samples per symbol
68 @param bits_per_symbol number of bits per symbol
69 @param access_code AKA sync vector
70 @param pad_for_usrp If true, packets are padded such that they end up a multiple of 128 samples
71 @param payload_length number of bytes in a data-stream slice
74 self._item_size_in = item_size_in
75 self._samples_per_symbol = samples_per_symbol
76 self._bits_per_symbol = bits_per_symbol
77 self._pad_for_usrp = pad_for_usrp
78 if not access_code: #get access code
79 access_code = packet_utils.default_access_code
80 if not packet_utils.is_1_0_string(access_code):
81 raise ValueError, "Invalid access_code %r. Must be string of 1's and 0's" % (access_code,)
82 self._access_code = access_code
83 self._pad_for_usrp = pad_for_usrp
84 if payload_length < 0: #get payload length
85 payload_length = DEFAULT_PAYLOAD_LEN
86 if payload_length%self._item_size_in != 0: #verify that packet length is a multiple of the stream size
87 raise ValueError, 'The packet length: "%d" is not a mutiple of the stream size: "%d".'%(payload_length, self._item_size_in)
88 self._payload_length = payload_length
90 msg_source = gr.message_source(gr.sizeof_char, DEFAULT_MSGQ_LIMIT)
91 self._msgq_out = msg_source.msgq()
92 self._msgq_in = gr.msg_queue(DEFAULT_MSGQ_LIMIT)
93 msg_sink = gr.message_sink(self._item_size_in, self._msgq_in, False) #False -> blocking
95 gr.hier_block2.__init__(
98 gr.io_signature(1, 1, self._item_size_in), # Input signature
99 gr.io_signature(1, 1, gr.sizeof_char) # Output signature
102 self.connect(self, msg_sink)
103 self.connect(msg_source, self)
105 _packet_encoder_thread(self._msgq_in, self._payload_length, self._send_packet)
107 def _send_packet(self, payload):
109 Wrap the payload in a packet and push onto the message queue.
110 @param payload string, data to send
112 packet = packet_utils.make_packet(
114 self._samples_per_symbol,
115 self._bits_per_symbol,
119 msg = gr.message_from_string(packet)
120 self._msgq_out.insert_tail(msg)
122 #######################################################################################
124 #######################################################################################
126 class _packet_decoder_thread(_threading.Thread):
128 def __init__(self, msgq, callback):
129 _threading.Thread.__init__(self)
132 self.callback = callback
133 self.keep_running = True
137 while self.keep_running:
138 msg = self._msgq.delete_head()
139 ok, payload = packet_utils.unmake_packet(msg.to_string(), int(msg.arg1()))
141 self.callback(ok, payload)
143 class packet_decoder(gr.hier_block2):
145 Hierarchical block for wrapping packet-based demodulators.
148 def __init__(self, item_size_out, access_code='', threshold=-1):
150 packet_demod constructor.
151 @param item_size_out the size of the output data stream in bytes
152 @param access_code AKA sync vector
153 @param threshold detect access_code with up to threshold bits wrong (-1 -> use default)
156 self._item_size_out = item_size_out
158 if not access_code: #get access code
159 access_code = packet_utils.default_access_code
160 if not packet_utils.is_1_0_string(access_code):
161 raise ValueError, "Invalid access_code %r. Must be string of 1's and 0's" % (access_code,)
162 self._access_code = access_code
164 if threshold < 0: threshold = DEFAULT_THRESHOLD
165 self._threshold = threshold
167 self._msgq_in = gr.msg_queue(DEFAULT_MSGQ_LIMIT) #holds packets from the PHY
168 correlator = gr.correlate_access_code_bb(self._access_code, self._threshold)
169 framer_sink = gr.framer_sink_1(self._msgq_in)
170 msg_source = gr.message_source(self._item_size_out, DEFAULT_MSGQ_LIMIT)
171 self._msgq_out = msg_source.msgq()
173 gr.hier_block2.__init__(
176 gr.io_signature(1, 1, gr.sizeof_char), # Input signature
177 gr.io_signature(1, 1, self._item_size_out) # Output signature
180 self.connect(self, correlator, framer_sink)
181 self.connect(msg_source, self)
183 _packet_decoder_thread(self._msgq_in, self._recv_packet)
185 def _recv_packet(self, ok, payload):
187 Extract the payload from the packet and push onto message queue.
189 @param payload data received
191 msg = gr.message_from_string(payload, 0, self._item_size_out, len(payload)/self._item_size_out)
192 if ok: self._msgq_out.insert_tail(msg)