diff options
author | Manoj Gudi | 2013-10-07 20:19:55 +0530 |
---|---|---|
committer | Manoj Gudi | 2013-10-07 20:20:35 +0530 |
commit | 1826d0763c8595997f5f4af1fdb0354e9c0998ad (patch) | |
tree | acbd852cd5a1bf17241b1038b5e37a0e72e64612 /grc/grc_gnuradio/blks2 | |
parent | 452defdb4a78e9e826740ddf4b9673e926c568a4 (diff) | |
parent | 24b640997ba7fee0c725e65f401f5cbebdab8d08 (diff) | |
download | gnuradio-1826d0763c8595997f5f4af1fdb0354e9c0998ad.tar.gz gnuradio-1826d0763c8595997f5f4af1fdb0354e9c0998ad.tar.bz2 gnuradio-1826d0763c8595997f5f4af1fdb0354e9c0998ad.zip |
README change
Diffstat (limited to 'grc/grc_gnuradio/blks2')
-rw-r--r-- | grc/grc_gnuradio/blks2/__init__.py | 26 | ||||
-rw-r--r-- | grc/grc_gnuradio/blks2/error_rate.py | 137 | ||||
-rw-r--r-- | grc/grc_gnuradio/blks2/packet.py | 242 | ||||
-rw-r--r-- | grc/grc_gnuradio/blks2/selector.py | 128 | ||||
-rw-r--r-- | grc/grc_gnuradio/blks2/tcp.py | 66 |
5 files changed, 599 insertions, 0 deletions
diff --git a/grc/grc_gnuradio/blks2/__init__.py b/grc/grc_gnuradio/blks2/__init__.py new file mode 100644 index 000000000..fde76f256 --- /dev/null +++ b/grc/grc_gnuradio/blks2/__init__.py @@ -0,0 +1,26 @@ +# Copyright 2008-2011 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 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +from selector import selector, valve +from packet import options, packet_encoder, packet_decoder, \ + packet_mod_b, packet_mod_s, packet_mod_i, packet_mod_f, packet_mod_c, \ + packet_demod_b, packet_demod_s, packet_demod_i, packet_demod_f, packet_demod_c +from error_rate import error_rate +from tcp import tcp_source, tcp_sink diff --git a/grc/grc_gnuradio/blks2/error_rate.py b/grc/grc_gnuradio/blks2/error_rate.py new file mode 100644 index 000000000..9b2df58ef --- /dev/null +++ b/grc/grc_gnuradio/blks2/error_rate.py @@ -0,0 +1,137 @@ +# Copyright 2008 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 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +default_win_size = 1000 + +from gnuradio import gr +import gnuradio.gr.gr_threading as _threading +import numpy + +#generate 1s counts array +_1s_counts = [sum([1&(i>>j) for j in range(8)]) for i in range(2**8)] + +class input_watcher(_threading.Thread): + """ + Read samples from the message queue and hand them to the callback. + """ + + def __init__(self, msgq, callback): + self._msgq = msgq + self._callback = callback + _threading.Thread.__init__(self) + self.setDaemon(1) + self.keep_running = True + self.start() + + def run(self): + r = '' + while True: + msg = self._msgq.delete_head() + itemsize = int(msg.arg1()) + nitems = int(msg.arg2()) + s = r + msg.to_string() + i = (nitems-nitems%2)*itemsize + r = s[i:] + s = s[:i] + samples = numpy.fromstring(s, numpy.int8) + self._callback(samples) + +class error_rate(gr.hier_block2): + """ + Sample the incoming data streams (byte) and calculate the bit or symbol error rate. + Write the running rate to the output data stream (float). + """ + + def __init__(self, type='BER', win_size=default_win_size, bits_per_symbol=2): + """ + Error rate constructor. + @param type a string 'BER' or 'SER' + @param win_size the number of samples to calculate over + @param bits_per_symbol the number of information bits per symbol (BER only) + """ + #init + gr.hier_block2.__init__( + self, 'error_rate', + gr.io_signature(2, 2, gr.sizeof_char), + gr.io_signature(1, 1, gr.sizeof_float), + ) + assert type in ('BER', 'SER') + self._max_samples = win_size + self._bits_per_symbol = bits_per_symbol + #setup message queue + msg_source = gr.message_source(gr.sizeof_float, 1) + self._msgq_source = msg_source.msgq() + msgq_sink = gr.msg_queue(2) + msg_sink = gr.message_sink(gr.sizeof_char, msgq_sink, False) #False -> blocking + inter = gr.interleave(gr.sizeof_char) + #start thread + self._num_errs = 0 + self._err_index = 0 + self._num_samps = 0 + self._err_array = numpy.zeros(self._max_samples, numpy.int8) + if type == 'BER': + input_watcher(msgq_sink, self._handler_ber) + elif type == 'SER': + input_watcher(msgq_sink, self._handler_ser) + #connect + self.connect(msg_source, self) + self.connect((self, 0), (inter, 0)) + self.connect((self, 1), (inter, 1)) + self.connect(inter, msg_sink) + + def _handler_ber(self, samples): + num = len(samples)/2 + arr = numpy.zeros(num, numpy.float32) + for i in range(num): + old_err = self._err_array[self._err_index] + #record error + self._err_array[self._err_index] = _1s_counts[samples[i*2] ^ samples[i*2 + 1]] + self._num_errs = self._num_errs + self._err_array[self._err_index] - old_err + #increment index + self._err_index = (self._err_index + 1)%self._max_samples + self._num_samps = min(self._num_samps + 1, self._max_samples) + #write sample + arr[i] = float(self._num_errs)/float(self._num_samps*self._bits_per_symbol) + #write message + msg = gr.message_from_string(arr.tostring(), 0, gr.sizeof_float, num) + self._msgq_source.insert_tail(msg) + + def _handler_ser(self, samples): + num = len(samples)/2 + arr = numpy.zeros(num, numpy.float32) + for i in range(num): + old_err = self._err_array[self._err_index] + #record error + ref = samples[i*2] + res = samples[i*2 + 1] + if ref == res: + self._err_array[self._err_index] = 0 + else: + self._err_array[self._err_index] = 1 + #update number of errors + self._num_errs = self._num_errs + self._err_array[self._err_index] - old_err + #increment index + self._err_index = (self._err_index + 1)%self._max_samples + self._num_samps = min(self._num_samps + 1, self._max_samples) + #write sample + arr[i] = float(self._num_errs)/float(self._num_samps) + #write message + msg = gr.message_from_string(arr.tostring(), 0, gr.sizeof_float, num) + self._msgq_source.insert_tail(msg) diff --git a/grc/grc_gnuradio/blks2/packet.py b/grc/grc_gnuradio/blks2/packet.py new file mode 100644 index 000000000..e39f55c84 --- /dev/null +++ b/grc/grc_gnuradio/blks2/packet.py @@ -0,0 +1,242 @@ +# Copyright 2008, 2009 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 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +from gnuradio import gr, digital +from gnuradio.digital import packet_utils +import gnuradio.gr.gr_threading as _threading + +##payload length in bytes +DEFAULT_PAYLOAD_LEN = 512 + +##how many messages in a queue +DEFAULT_MSGQ_LIMIT = 2 + +##threshold for unmaking packets +DEFAULT_THRESHOLD = 12 + +################################################## +## Options Class for OFDM +################################################## +class options(object): + def __init__(self, **kwargs): + for key, value in kwargs.iteritems(): setattr(self, key, value) + +################################################## +## Packet Encoder +################################################## +class _packet_encoder_thread(_threading.Thread): + + def __init__(self, msgq, payload_length, send): + self._msgq = msgq + self._payload_length = payload_length + self._send = send + _threading.Thread.__init__(self) + self.setDaemon(1) + self.keep_running = True + self.start() + + def run(self): + sample = '' #residual sample + while self.keep_running: + msg = self._msgq.delete_head() #blocking read of message queue + sample = sample + msg.to_string() #get the body of the msg as a string + while len(sample) >= self._payload_length: + payload = sample[:self._payload_length] + sample = sample[self._payload_length:] + self._send(payload) + +class packet_encoder(gr.hier_block2): + """ + Hierarchical block for wrapping packet-based modulators. + """ + + def __init__(self, samples_per_symbol, bits_per_symbol, access_code='', pad_for_usrp=True): + """ + packet_mod constructor. + @param samples_per_symbol number of samples per symbol + @param bits_per_symbol number of bits per symbol + @param access_code AKA sync vector + @param pad_for_usrp If true, packets are padded such that they end up a multiple of 128 samples + @param payload_length number of bytes in a data-stream slice + """ + #setup parameters + self._samples_per_symbol = samples_per_symbol + self._bits_per_symbol = bits_per_symbol + self._pad_for_usrp = pad_for_usrp + if not access_code: #get access code + access_code = packet_utils.default_access_code + if not packet_utils.is_1_0_string(access_code): + raise ValueError, "Invalid access_code %r. Must be string of 1's and 0's" % (access_code,) + self._access_code = access_code + self._pad_for_usrp = pad_for_usrp + #create blocks + msg_source = gr.message_source(gr.sizeof_char, DEFAULT_MSGQ_LIMIT) + self._msgq_out = msg_source.msgq() + #initialize hier2 + gr.hier_block2.__init__( + self, + "packet_encoder", + gr.io_signature(0, 0, 0), # Input signature + gr.io_signature(1, 1, gr.sizeof_char) # Output signature + ) + #connect + self.connect(msg_source, self) + + def send_pkt(self, payload): + """ + Wrap the payload in a packet and push onto the message queue. + @param payload string, data to send + """ + packet = packet_utils.make_packet( + payload, + self._samples_per_symbol, + self._bits_per_symbol, + self._access_code, + self._pad_for_usrp + ) + msg = gr.message_from_string(packet) + self._msgq_out.insert_tail(msg) + +################################################## +## Packet Decoder +################################################## +class _packet_decoder_thread(_threading.Thread): + + def __init__(self, msgq, callback): + _threading.Thread.__init__(self) + self.setDaemon(1) + self._msgq = msgq + self.callback = callback + self.keep_running = True + self.start() + + def run(self): + while self.keep_running: + msg = self._msgq.delete_head() + ok, payload = packet_utils.unmake_packet(msg.to_string(), int(msg.arg1())) + if self.callback: + self.callback(ok, payload) + +class packet_decoder(gr.hier_block2): + """ + Hierarchical block for wrapping packet-based demodulators. + """ + + def __init__(self, access_code='', threshold=-1, callback=None): + """ + packet_demod constructor. + @param access_code AKA sync vector + @param threshold detect access_code with up to threshold bits wrong (0 -> use default) + @param callback a function of args: ok, payload + """ + #access code + if not access_code: #get access code + access_code = packet_utils.default_access_code + if not packet_utils.is_1_0_string(access_code): + raise ValueError, "Invalid access_code %r. Must be string of 1's and 0's" % (access_code,) + self._access_code = access_code + #threshold + if threshold < 0: threshold = DEFAULT_THRESHOLD + self._threshold = threshold + #blocks + msgq = gr.msg_queue(DEFAULT_MSGQ_LIMIT) #holds packets from the PHY + correlator = digital.correlate_access_code_bb(self._access_code, self._threshold) + framer_sink = gr.framer_sink_1(msgq) + #initialize hier2 + gr.hier_block2.__init__( + self, + "packet_decoder", + gr.io_signature(1, 1, gr.sizeof_char), # Input signature + gr.io_signature(0, 0, 0) # Output signature + ) + #connect + self.connect(self, correlator, framer_sink) + #start thread + _packet_decoder_thread(msgq, callback) + +################################################## +## Packet Mod for OFDM Mod and Packet Encoder +################################################## +class packet_mod_base(gr.hier_block2): + """ + Hierarchical block for wrapping packet source block. + """ + + def __init__(self, packet_source=None, payload_length=0): + if not payload_length: #get payload length + payload_length = DEFAULT_PAYLOAD_LEN + if payload_length%self._item_size_in != 0: #verify that packet length is a multiple of the stream size + raise ValueError, 'The payload length: "%d" is not a mutiple of the stream size: "%d".'%(payload_length, self._item_size_in) + #initialize hier2 + gr.hier_block2.__init__( + self, + "ofdm_mod", + gr.io_signature(1, 1, self._item_size_in), # Input signature + gr.io_signature(1, 1, packet_source._hb.output_signature().sizeof_stream_item(0)) # Output signature + ) + #create blocks + msgq = gr.msg_queue(DEFAULT_MSGQ_LIMIT) + msg_sink = gr.message_sink(self._item_size_in, msgq, False) #False -> blocking + #connect + self.connect(self, msg_sink) + self.connect(packet_source, self) + #start thread + _packet_encoder_thread(msgq, payload_length, packet_source.send_pkt) + +class packet_mod_b(packet_mod_base): _item_size_in = gr.sizeof_char +class packet_mod_s(packet_mod_base): _item_size_in = gr.sizeof_short +class packet_mod_i(packet_mod_base): _item_size_in = gr.sizeof_int +class packet_mod_f(packet_mod_base): _item_size_in = gr.sizeof_float +class packet_mod_c(packet_mod_base): _item_size_in = gr.sizeof_gr_complex + +################################################## +## Packet Demod for OFDM Demod and Packet Decoder +################################################## +class packet_demod_base(gr.hier_block2): + """ + Hierarchical block for wrapping packet sink block. + """ + + def __init__(self, packet_sink=None): + #initialize hier2 + gr.hier_block2.__init__( + self, + "ofdm_mod", + gr.io_signature(1, 1, packet_sink._hb.input_signature().sizeof_stream_item(0)), # Input signature + gr.io_signature(1, 1, self._item_size_out) # Output signature + ) + #create blocks + msg_source = gr.message_source(self._item_size_out, DEFAULT_MSGQ_LIMIT) + self._msgq_out = msg_source.msgq() + #connect + self.connect(self, packet_sink) + self.connect(msg_source, self) + if packet_sink._hb.output_signature().sizeof_stream_item(0): + self.connect(packet_sink, gr.null_sink(packet_sink._hb.output_signature().sizeof_stream_item(0))) + + def recv_pkt(self, ok, payload): + msg = gr.message_from_string(payload, 0, self._item_size_out, len(payload)/self._item_size_out) + if ok: self._msgq_out.insert_tail(msg) + +class packet_demod_b(packet_demod_base): _item_size_out = gr.sizeof_char +class packet_demod_s(packet_demod_base): _item_size_out = gr.sizeof_short +class packet_demod_i(packet_demod_base): _item_size_out = gr.sizeof_int +class packet_demod_f(packet_demod_base): _item_size_out = gr.sizeof_float +class packet_demod_c(packet_demod_base): _item_size_out = gr.sizeof_gr_complex diff --git a/grc/grc_gnuradio/blks2/selector.py b/grc/grc_gnuradio/blks2/selector.py new file mode 100644 index 000000000..f0f6d5dd7 --- /dev/null +++ b/grc/grc_gnuradio/blks2/selector.py @@ -0,0 +1,128 @@ +# +# Copyright 2008 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 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +from gnuradio import gr + +class selector(gr.hier_block2): + """A hier2 block with N inputs and M outputs, where data is only forwarded through input n to output m.""" + def __init__(self, item_size, num_inputs, num_outputs, input_index, output_index): + """ + Selector constructor. + @param item_size the size of the gr data stream in bytes + @param num_inputs the number of inputs (integer) + @param num_outputs the number of outputs (integer) + @param input_index the index for the source data + @param output_index the index for the destination data + """ + gr.hier_block2.__init__( + self, 'selector', + gr.io_signature(num_inputs, num_inputs, item_size), + gr.io_signature(num_outputs, num_outputs, item_size), + ) + #terminator blocks for unused inputs and outputs + self.input_terminators = [gr.null_sink(item_size) for i in range(num_inputs)] + self.output_terminators = [gr.head(item_size, 0) for i in range(num_outputs)] + self.copy = gr.kludge_copy(item_size) + #connections + for i in range(num_inputs): self.connect((self, i), self.input_terminators[i]) + for i in range(num_outputs): self.connect(gr.null_source(item_size), self.output_terminators[i], (self, i)) + self.item_size = item_size + self.input_index = input_index + self.output_index = output_index + self.num_inputs = num_inputs + self.num_outputs = num_outputs + self._connect_current() + + def _indexes_valid(self): + """ + Are the input and output indexes within range of the number of inputs and outputs? + @return true if input index and output index are in range + """ + return self.input_index in range(self.num_inputs) and self.output_index in range(self.num_outputs) + + def _connect_current(self): + """If the input and output indexes are valid: + disconnect the blocks at the input and output index from their terminators, + and connect them to one another. Then connect the terminators to one another.""" + if self._indexes_valid(): + self.disconnect((self, self.input_index), self.input_terminators[self.input_index]) + self.disconnect(self.output_terminators[self.output_index], (self, self.output_index)) + self.connect((self, self.input_index), self.copy) + self.connect(self.copy, (self, self.output_index)) + self.connect(self.output_terminators[self.output_index], self.input_terminators[self.input_index]) + + def _disconnect_current(self): + """If the input and output indexes are valid: + disconnect the blocks at the input and output index from one another, + and the terminators at the input and output index from one another. + Reconnect the blocks to the terminators.""" + if self._indexes_valid(): + self.disconnect((self, self.input_index), self.copy) + self.disconnect(self.copy, (self, self.output_index)) + self.disconnect(self.output_terminators[self.output_index], self.input_terminators[self.input_index]) + self.connect((self, self.input_index), self.input_terminators[self.input_index]) + self.connect(self.output_terminators[self.output_index], (self, self.output_index)) + + def set_input_index(self, input_index): + """ + Change the block to the new input index if the index changed. + @param input_index the new input index + """ + if self.input_index != input_index: + self.lock() + self._disconnect_current() + self.input_index = input_index + self._connect_current() + self.unlock() + + def set_output_index(self, output_index): + """ + Change the block to the new output index if the index changed. + @param output_index the new output index + """ + if self.output_index != output_index: + self.lock() + self._disconnect_current() + self.output_index = output_index + self._connect_current() + self.unlock() + +class valve(selector): + """Wrapper for selector with 1 input and 1 output.""" + + def __init__(self, item_size, open): + """ + Constructor for valve. + @param item_size the size of the gr data stream in bytes + @param open true if initial valve state is open + """ + if open: output_index = -1 + else: output_index = 0 + selector.__init__(self, item_size, 1, 1, 0, output_index) + + def set_open(self, open): + """ + Callback to set open state. + @param open true to set valve state to open + """ + if open: output_index = -1 + else: output_index = 0 + self.set_output_index(output_index) diff --git a/grc/grc_gnuradio/blks2/tcp.py b/grc/grc_gnuradio/blks2/tcp.py new file mode 100644 index 000000000..c6739b711 --- /dev/null +++ b/grc/grc_gnuradio/blks2/tcp.py @@ -0,0 +1,66 @@ +# +# Copyright 2009 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 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +from gnuradio import gr +import socket +import os + +def _get_sock_fd(addr, port, server): + """ + Get the file descriptor for the socket. + As a client, block on connect, dup the socket descriptor. + As a server, block on accept, dup the client descriptor. + @param addr the ip address string + @param port the tcp port number + @param server true for server mode, false for client mode + @return the file descriptor number + """ + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + if server: + sock.bind((addr, port)) + sock.listen(1) + clientsock, address = sock.accept() + return os.dup(clientsock.fileno()) + else: + sock.connect((addr, port)) + return os.dup(sock.fileno()) + +class tcp_source(gr.hier_block2): + def __init__(self, itemsize, addr, port, server=True): + #init hier block + gr.hier_block2.__init__( + self, 'tcp_source', + gr.io_signature(0, 0, 0), + gr.io_signature(1, 1, itemsize), + ) + fd = _get_sock_fd(addr, port, server) + self.connect(gr.file_descriptor_source(itemsize, fd), self) + +class tcp_sink(gr.hier_block2): + def __init__(self, itemsize, addr, port, server=False): + #init hier block + gr.hier_block2.__init__( + self, 'tcp_sink', + gr.io_signature(1, 1, itemsize), + gr.io_signature(0, 0, 0), + ) + fd = _get_sock_fd(addr, port, server) + self.connect(self, gr.file_descriptor_sink(itemsize, fd)) |