From 9967e2e7664dbc96a5d1587c194cc648d01cf487 Mon Sep 17 00:00:00 2001 From: trondeau Date: Sat, 4 Aug 2007 15:21:34 +0000 Subject: [PATCH] merged -r5966:6112 on trondeau/ofdm_mod. Allows for generic constellations (supports bpsk, qpsk, 8psk, qam16, qam64, and qam256 currently), fixes some bugs in the correlation and altered default parameters for over-the-air operation. This merge fixes ticket:156 and ticket:157. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@6113 221aa14e-8319-0410-a670-987f0aec2ac5 --- gnuradio-core/src/lib/general/general.i | 2 + .../src/lib/general/gr_ofdm_bpsk_mapper.cc | 4 +- .../src/lib/general/gr_ofdm_correlator.cc | 28 +- .../src/lib/general/gr_ofdm_correlator.h | 2 +- .../src/lib/general/gr_ofdm_frame_sink.cc | 126 ++--- .../src/lib/general/gr_ofdm_frame_sink.h | 38 +- .../src/lib/general/gr_ofdm_frame_sink.i | 10 +- .../src/lib/general/gr_ofdm_mapper_bcv.cc | 156 ++++++- .../src/lib/general/gr_ofdm_mapper_bcv.h | 48 +- .../src/lib/general/gr_ofdm_mapper_bcv.i | 26 +- .../src/lib/general/gr_ofdm_qpsk_mapper.cc | 4 +- .../src/lib/general/gr_ofdm_sampler.cc | 4 +- .../src/python/gnuradio/blksimpl/ofdm.py | 51 +- .../src/python/gnuradio/blksimpl/psk.py | 6 + .../src/python/gnuradio/gruimpl/crc.py | 4 +- .../python/ofdm/benchmark_ofdm.py | 14 +- .../python/ofdm/benchmark_ofdm_rx.py | 2 +- .../python/ofdm/benchmark_ofdm_tx.py | 4 +- gnuradio-examples/python/ofdm/receive_path.py | 8 +- .../python/ofdm/transmit_path.py | 2 +- gnuradio-examples/python/ofdm/tunnel.py | 435 ++++++++++++++++++ 21 files changed, 826 insertions(+), 148 deletions(-) create mode 100755 gnuradio-examples/python/ofdm/tunnel.py diff --git a/gnuradio-core/src/lib/general/general.i b/gnuradio-core/src/lib/general/general.i index a6a356f4..e9780ea1 100644 --- a/gnuradio-core/src/lib/general/general.i +++ b/gnuradio-core/src/lib/general/general.i @@ -96,6 +96,7 @@ #include #include #include +#include #include #include #include @@ -203,6 +204,7 @@ %include "gr_ofdm_correlator.i" %include "gr_ofdm_cyclic_prefixer.i" %include "gr_ofdm_bpsk_demapper.i" +%include "gr_ofdm_mapper_bcv.i" %include "gr_ofdm_bpsk_mapper.i" %include "gr_ofdm_qpsk_mapper.i" %include "gr_ofdm_qam_mapper.i" diff --git a/gnuradio-core/src/lib/general/gr_ofdm_bpsk_mapper.cc b/gnuradio-core/src/lib/general/gr_ofdm_bpsk_mapper.cc index da328868..f634ed3f 100644 --- a/gnuradio-core/src/lib/general/gr_ofdm_bpsk_mapper.cc +++ b/gnuradio-core/src/lib/general/gr_ofdm_bpsk_mapper.cc @@ -59,7 +59,7 @@ static float randombit() { int r = rand()&1; - return (float)(-1 + 2*r); + return (float)(1 - 2*r); } int @@ -105,7 +105,7 @@ gr_ofdm_bpsk_mapper::work(int noutput_items, i = 0; while((d_msg_offset < d_msg->length()) && (i < d_occupied_carriers)) { unsigned char bit = (d_msg->msg()[d_msg_offset] >> (d_bit_offset)) & 0x01; - out[i + zeros_on_left] = gr_complex(-1+2*(bit)); + out[i + zeros_on_left] = gr_complex(1-2*(bit)); i++; d_bit_offset++; if(d_bit_offset == 8) { diff --git a/gnuradio-core/src/lib/general/gr_ofdm_correlator.cc b/gnuradio-core/src/lib/general/gr_ofdm_correlator.cc index 4c7b67ff..e396eeb8 100644 --- a/gnuradio-core/src/lib/general/gr_ofdm_correlator.cc +++ b/gnuradio-core/src/lib/general/gr_ofdm_correlator.cc @@ -99,12 +99,13 @@ gr_ofdm_correlator::coarse_freq_comp(int freq_delta, int symbol_count) { // return gr_complex(cos(-M_TWOPI*freq_delta*d_cplen/d_fft_length*symbol_count), // sin(-M_TWOPI*freq_delta*d_cplen/d_fft_length*symbol_count)); - //return gr_expj(-M_TWOPI*freq_delta*d_cplen/d_fft_length*symbol_count); - assert(d_freq_shift_len + freq_delta >= 0); - assert(symbol_count <= MAX_NUM_SYMBOLS); + return gr_expj(-M_TWOPI*freq_delta*d_cplen/d_fft_length*symbol_count); - return d_phase_lut[MAX_NUM_SYMBOLS * (d_freq_shift_len + freq_delta) + symbol_count]; + //assert(d_freq_shift_len + freq_delta >= 0); + //assert(symbol_count <= MAX_NUM_SYMBOLS); + + //return d_phase_lut[MAX_NUM_SYMBOLS * (d_freq_shift_len + freq_delta) + symbol_count]; } bool @@ -118,7 +119,7 @@ gr_ofdm_correlator::correlate(const gr_complex *previous, const gr_complex *curr gr_complex h_sqrd = gr_complex(0.0,0.0); float power = 0.0F; - while(!found && ((unsigned)abs(search_delta) < d_freq_shift_len)) { + while(!found && ((unsigned)abs(search_delta) <= d_freq_shift_len)) { h_sqrd = gr_complex(0.0,0.0); power = 0.0F; @@ -126,17 +127,18 @@ gr_ofdm_correlator::correlate(const gr_complex *previous, const gr_complex *curr h_sqrd = h_sqrd + previous[i+zeros_on_left+search_delta] * conj(coarse_freq_comp(search_delta,1)*current[i+zeros_on_left+search_delta]) * d_diff_corr_factor[i]; + power = power + norm(current[i+zeros_on_left+search_delta]); // No need to do coarse freq here } #if VERBOSE - printf("bin %d\th_sqrd = ( %f, %f )\t power = %f\t real(h)/p = %f\t angle = %f\n", - search_delta, h_sqrd.real(), h_sqrd.imag(), power, h_sqrd.real()/power, arg(h_sqrd)); -#endif - - // FIXME: Look at h_sqrd.read() > power - if((h_sqrd.real() > 0.82*power) && (h_sqrd.real() < 1.1 * power)) { + printf("bin %d\th_sqrd = ( %f, %f )\t power = %f\t real(h)/p = %f\t angle = %f\n", + search_delta, h_sqrd.real(), h_sqrd.imag(), power, h_sqrd.real()/power, arg(h_sqrd)); +#endif + // FIXME: Look at h_sqrd.read() > power + if((h_sqrd.real() > 0.82*power) && (h_sqrd.real() < 1.1 * power)) { found = true; + //printf("search delta: %d\n", search_delta); d_coarse_freq = search_delta; d_phase_count = 1; //d_snr_est = 10*log10(power/(power-h_sqrd.real())); @@ -220,6 +222,10 @@ gr_ofdm_correlator::general_work(int noutput_items, d_phase_count++; + if(d_phase_count == MAX_NUM_SYMBOLS) { + d_phase_count = 1; + } + consume_each(1); return 1; } diff --git a/gnuradio-core/src/lib/general/gr_ofdm_correlator.h b/gnuradio-core/src/lib/general/gr_ofdm_correlator.h index 981df7e1..55ee4e19 100644 --- a/gnuradio-core/src/lib/general/gr_ofdm_correlator.h +++ b/gnuradio-core/src/lib/general/gr_ofdm_correlator.h @@ -35,7 +35,7 @@ gr_make_ofdm_correlator (unsigned int occupied_carriers, unsigned int fft_length unsigned int cplen, const std::vector &known_symbol1, const std::vector &known_symbol2, - unsigned int max_fft_shift_len=4); + unsigned int max_fft_shift_len=10); /*! * \brief take a vector of complex constellation points in from an FFT diff --git a/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.cc b/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.cc index 68cadce0..d75b693a 100644 --- a/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.cc +++ b/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.cc @@ -74,55 +74,57 @@ gr_ofdm_frame_sink::enter_have_header() d_packetlen, d_packet_whitener_offset); } -unsigned char gr_ofdm_frame_sink::bpsk_slicer(gr_complex x) -{ - return (unsigned char)(x.real() > 0 ? 1 : 0); -} - -unsigned char gr_ofdm_frame_sink::qpsk_slicer(gr_complex x) -{ - unsigned char i = (x.real() > 0 ? 1 : 0); - unsigned char q = (x.imag() > 0 ? 1 : 0); - - return (q << 1) | i; -} -unsigned int gr_ofdm_frame_sink::bpsk_demapper(const gr_complex *in, - unsigned char *out) +unsigned char gr_ofdm_frame_sink::slicer(const gr_complex x) { - unsigned int i=0, bytes_produced=0; - - while(i < d_occupied_carriers) { - - while((d_byte_offset < 8) && (i < d_occupied_carriers)) { - //fprintf(stderr, "%f+j%f\n", in[i].real(), in[i].imag()); - d_partial_byte |= bpsk_slicer(in[i++]) << (d_byte_offset++); - } - - if(d_byte_offset == 8) { - out[bytes_produced++] = d_partial_byte; - d_byte_offset = 0; - d_partial_byte = 0; + unsigned int table_size = d_sym_value_out.size(); + unsigned int min_index = 0; + float min_euclid_dist = norm(x - d_sym_position[0]); + float euclid_dist = 0; + + for (unsigned int j = 1; j < table_size; j++){ + euclid_dist = norm(x - d_sym_position[j]); + if (euclid_dist < min_euclid_dist){ + min_euclid_dist = euclid_dist; + min_index = j; } } - - return bytes_produced; + return d_sym_value_out[min_index]; } -unsigned int gr_ofdm_frame_sink::qpsk_demapper(const gr_complex *in, - unsigned char *out) +unsigned int gr_ofdm_frame_sink::demapper(const gr_complex *in, + unsigned char *out) { unsigned int i=0, bytes_produced=0; while(i < d_occupied_carriers) { - + if(d_nresid > 0) { + d_partial_byte |= d_resid; + d_byte_offset += d_nresid; + d_nresid = 0; + d_resid = 0; + } + while((d_byte_offset < 8) && (i < d_occupied_carriers)) { - //fprintf(stderr, "%f+j%f\n", in[i].real(), in[i].imag()); - d_partial_byte |= qpsk_slicer(in[i++]) << (d_byte_offset); - d_byte_offset += 2; + //fprintf(stderr, "%f+j%f = %d\n", in[i].real(), in[i].imag(), slicer(in[i])); + unsigned char bits = slicer(in[i++]); + if((8 - d_byte_offset) >= d_nbits) { + d_partial_byte |= bits << (d_byte_offset); + d_byte_offset += d_nbits; + } + else { + d_nresid = d_nbits-(8-d_byte_offset); + int mask = ((1<<(8-d_byte_offset))-1); + d_partial_byte |= (bits & mask) << d_byte_offset; + d_resid = bits >> (8-d_byte_offset); + d_byte_offset += (d_nbits - d_nresid); + } + //printf("demod symbol: %.4f + j%.4f bits: %x partial_byte: %x byte_offset: %d resid: %x nresid: %d\n", + // in[i-1].real(), in[i-1].imag(), bits, d_partial_byte, d_byte_offset, d_resid, d_nresid); } if(d_byte_offset == 8) { + //printf("demod byte: %x \n\n", d_partial_byte); out[bytes_produced++] = d_partial_byte; d_byte_offset = 0; d_partial_byte = 0; @@ -132,34 +134,31 @@ unsigned int gr_ofdm_frame_sink::qpsk_demapper(const gr_complex *in, return bytes_produced; } + gr_ofdm_frame_sink_sptr -gr_make_ofdm_frame_sink(gr_msg_queue_sptr target_queue, unsigned int occupied_carriers, - const std::string &mod) +gr_make_ofdm_frame_sink(const std::vector &sym_position, + const std::vector &sym_value_out, + gr_msg_queue_sptr target_queue, unsigned int occupied_carriers) { - return gr_ofdm_frame_sink_sptr(new gr_ofdm_frame_sink(target_queue, occupied_carriers, mod)); + return gr_ofdm_frame_sink_sptr(new gr_ofdm_frame_sink(sym_position, sym_value_out, + target_queue, occupied_carriers)); } -gr_ofdm_frame_sink::gr_ofdm_frame_sink(gr_msg_queue_sptr target_queue, unsigned int occupied_carriers, - const std::string &mod) +gr_ofdm_frame_sink::gr_ofdm_frame_sink(const std::vector &sym_position, + const std::vector &sym_value_out, + gr_msg_queue_sptr target_queue, unsigned int occupied_carriers) : gr_sync_block ("ofdm_frame_sink", gr_make_io_signature2 (2, 2, sizeof(gr_complex)*occupied_carriers, sizeof(char)), gr_make_io_signature (0, 0, 0)), d_target_queue(target_queue), d_occupied_carriers(occupied_carriers), - d_byte_offset(0), d_partial_byte(0) + d_byte_offset(0), d_partial_byte(0), + d_resid(0), d_nresid(0) { - d_bytes_out = new unsigned char[(int)ceil(d_occupied_carriers/4.0)]; - - if(mod == "qpsk") { - d_demapper = &gr_ofdm_frame_sink::qpsk_demapper; - } - else if(mod == "bpsk") { - d_demapper = &gr_ofdm_frame_sink::bpsk_demapper; - } - else { - throw std::invalid_argument("Modulation type must be BPSK or QPSK."); - } + d_bytes_out = new unsigned char[d_occupied_carriers]; + set_sym_value_out(sym_position, sym_value_out); + enter_search(); } @@ -168,6 +167,24 @@ gr_ofdm_frame_sink::~gr_ofdm_frame_sink () delete [] d_bytes_out; } +bool +gr_ofdm_frame_sink::set_sym_value_out(const std::vector &sym_position, + const std::vector &sym_value_out) +{ + if (sym_position.size() != sym_value_out.size()) + return false; + + if (sym_position.size()<1) + return false; + + d_sym_position = sym_position; + d_sym_value_out = sym_value_out; + d_nbits = (unsigned long)(log10(d_sym_value_out.size()) / log10(2)); + + return true; +} + + int gr_ofdm_frame_sink::work (int noutput_items, gr_vector_const_void_star &input_items, @@ -181,9 +198,8 @@ gr_ofdm_frame_sink::work (int noutput_items, if (VERBOSE) fprintf(stderr,">>> Entering state machine\n"); - //bytes = bpsk_demapper(&in[0], d_bytes_out); - bytes = (this->*d_demapper)(&in[0], d_bytes_out); - + bytes = demapper(&in[0], d_bytes_out); + switch(d_state) { case STATE_SYNC_SEARCH: // Look for flag indicating beginning of pkt diff --git a/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.h b/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.h index 13f61b78..f1c9b76f 100644 --- a/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.h +++ b/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.h @@ -30,8 +30,9 @@ class gr_ofdm_frame_sink; typedef boost::shared_ptr gr_ofdm_frame_sink_sptr; gr_ofdm_frame_sink_sptr -gr_make_ofdm_frame_sink (gr_msg_queue_sptr target_queue, unsigned int occupied_tones, - const std::string &mod); +gr_make_ofdm_frame_sink (const std::vector &sym_position, + const std::vector &sym_value_out, + gr_msg_queue_sptr target_queue, unsigned int occupied_tones); /*! * \brief Takes an OFDM symbol in, demaps it into bits of 0's and 1's, packs @@ -44,8 +45,9 @@ gr_make_ofdm_frame_sink (gr_msg_queue_sptr target_queue, unsigned int occupied_t class gr_ofdm_frame_sink : public gr_sync_block { friend gr_ofdm_frame_sink_sptr - gr_make_ofdm_frame_sink (gr_msg_queue_sptr target_queue, unsigned int occupied_tones, - const std::string &mod); + gr_make_ofdm_frame_sink (const std::vector &sym_position, + const std::vector &sym_value_out, + gr_msg_queue_sptr target_queue, unsigned int occupied_tones); private: enum state_t {STATE_SYNC_SEARCH, STATE_HAVE_SYNC, STATE_HAVE_HEADER}; @@ -69,9 +71,17 @@ class gr_ofdm_frame_sink : public gr_sync_block int d_packet_whitener_offset; // offset into whitener string to use int d_packetlen_cnt; // how many so far + std::vector d_sym_position; + std::vector d_sym_value_out; + unsigned int d_nbits; + + unsigned char d_resid; + unsigned int d_nresid; + protected: - gr_ofdm_frame_sink(gr_msg_queue_sptr target_queue, unsigned int occupied_tones, - const std::string &mod); + gr_ofdm_frame_sink(const std::vector &sym_position, + const std::vector &sym_value_out, + gr_msg_queue_sptr target_queue, unsigned int occupied_tones); void enter_search(); void enter_have_sync(); @@ -82,17 +92,13 @@ class gr_ofdm_frame_sink : public gr_sync_block // confirm that two copies of header info are identical return ((d_header >> 16) ^ (d_header & 0xffff)) == 0; } + + unsigned char slicer(const gr_complex x); + unsigned int demapper(const gr_complex *in, + unsigned char *out); - unsigned char bpsk_slicer(gr_complex x); - unsigned int bpsk_demapper(const gr_complex *in, - unsigned char *out); - - unsigned char qpsk_slicer(gr_complex x); - unsigned int qpsk_demapper(const gr_complex *in, - unsigned char *out); - - // pointer to mod-specific demapper - unsigned int (gr_ofdm_frame_sink::*d_demapper)(const gr_complex *in, unsigned char *out); + bool set_sym_value_out(const std::vector &sym_position, + const std::vector &sym_value_out); public: ~gr_ofdm_frame_sink(); diff --git a/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.i b/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.i index 4f4f81d2..296eb659 100644 --- a/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.i +++ b/gnuradio-core/src/lib/general/gr_ofdm_frame_sink.i @@ -23,14 +23,16 @@ GR_SWIG_BLOCK_MAGIC(gr,ofdm_frame_sink); gr_ofdm_frame_sink_sptr -gr_make_ofdm_frame_sink(gr_msg_queue_sptr target_queue, unsigned int occupied_tones, - const std::string &mod); +gr_make_ofdm_frame_sink(const std::vector &sym_position, + const std::vector &sym_value_out, + gr_msg_queue_sptr target_queue, unsigned int occupied_tones); class gr_ofdm_frame_sink : public gr_sync_block { protected: - gr_ofdm_frame_sink(gr_msg_queue_sptr target_queue, unsigned int occupied_tones, - const std::string &mod); + gr_ofdm_frame_sink(const std::vector &sym_position, + const std::vector &sym_value_out, + gr_msg_queue_sptr target_queue, unsigned int occupied_tones); public: ~gr_ofdm_frame_sink(); diff --git a/gnuradio-core/src/lib/general/gr_ofdm_mapper_bcv.cc b/gnuradio-core/src/lib/general/gr_ofdm_mapper_bcv.cc index 76a7c94d..4ff55b5d 100644 --- a/gnuradio-core/src/lib/general/gr_ofdm_mapper_bcv.cc +++ b/gnuradio-core/src/lib/general/gr_ofdm_mapper_bcv.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004,2005 Free Software Foundation, Inc. + * Copyright 2006,2007 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -20,22 +20,166 @@ * Boston, MA 02110-1301, USA. */ + #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include +#include + +gr_ofdm_mapper_bcv_sptr +gr_make_ofdm_mapper_bcv (const std::vector &constellation, unsigned int msgq_limit, + unsigned int occupied_carriers, unsigned int fft_length) +{ + return gr_ofdm_mapper_bcv_sptr (new gr_ofdm_mapper_bcv (constellation, msgq_limit, + occupied_carriers, fft_length)); +} + +// Consumes 1 packet and produces as many OFDM symbols of fft_length to hold the full packet +gr_ofdm_mapper_bcv::gr_ofdm_mapper_bcv (const std::vector &constellation, unsigned int msgq_limit, + unsigned int occupied_carriers, unsigned int fft_length) + : gr_sync_block ("ofdm_mapper_bcv", + gr_make_io_signature (0, 0, 0), + gr_make_io_signature2 (1, 2, sizeof(gr_complex)*fft_length, sizeof(char))), + d_constellation(constellation), + d_msgq(gr_make_msg_queue(msgq_limit)), d_msg_offset(0), d_eof(false), + d_occupied_carriers(occupied_carriers), + d_fft_length(fft_length), + d_bit_offset(0), + d_pending_flag(0), + d_resid(0), + d_nresid(0) +{ + if (!(d_occupied_carriers <= d_fft_length)) + throw std::invalid_argument("gr_ofdm_mapper_bcv: occupied carriers must be <= fft_length"); + + d_nbits = (unsigned long)(log10(d_constellation.size()) / log10(2)); +} gr_ofdm_mapper_bcv::~gr_ofdm_mapper_bcv(void) { } -gr_ofdm_mapper_bcv::gr_ofdm_mapper_bcv (unsigned bits_per_symbol,unsigned int vlen) - : gr_sync_decimator ("ofdm_mapper_bcv", - gr_make_io_signature (1, 1, sizeof(unsigned char)), - gr_make_io_signature (1, 1, sizeof(gr_complex)*vlen), - bits_per_symbol) +int gr_ofdm_mapper_bcv::randsym() { + return (rand() % d_constellation.size()); } +int +gr_ofdm_mapper_bcv::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + gr_complex *out = (gr_complex *)output_items[0]; + + unsigned int i=0; + unsigned int unoccupied_carriers = d_fft_length - d_occupied_carriers; + unsigned int zeros_on_left = (unsigned)ceil(unoccupied_carriers/2.0); + + //printf("OFDM BPSK Mapper: ninput_items: %d noutput_items: %d\n", ninput_items[0], noutput_items); + + if(d_eof) { + return -1; + } + + if(!d_msg) { + d_msg = d_msgq->delete_head(); // block, waiting for a message + d_msg_offset = 0; + d_bit_offset = 0; + d_pending_flag = 1; // new packet, write start of packet flag + + if((d_msg->length() == 0) && (d_msg->type() == 1)) { + d_msg.reset(); + return -1; // We're done; no more messages coming. + } + } + + char *out_flag = 0; + if(output_items.size() == 2) + out_flag = (char *) output_items[1]; + + + // Build a single symbol: + // Initialize all bins to 0 to set unused carriers + memset(out, 0, d_fft_length*sizeof(gr_complex)); + + i = 0; + unsigned char bits = 0; + while((d_msg_offset < d_msg->length()) && (i < d_occupied_carriers)) { + + // need new data to process + if(d_bit_offset == 0) { + d_msgbytes = d_msg->msg()[d_msg_offset]; + //printf("mod message byte: %x\n", d_msgbytes); + } + + if(d_nresid > 0) { + d_resid |= (((1 << d_nresid)-1) & d_msgbytes) << (d_nbits - d_nresid); + bits = d_resid; + + out[i + zeros_on_left] = d_constellation[bits]; + i++; + + d_bit_offset += d_nresid; + d_nresid = 0; + d_resid = 0; + //printf("mod bit(r): %x resid: %x nresid: %d bit_offset: %d\n", + // bits, d_resid, d_nresid, d_bit_offset); + } + else { + if((8 - d_bit_offset) >= d_nbits) { + bits = ((1 << d_nbits)-1) & (d_msgbytes >> d_bit_offset); + d_bit_offset += d_nbits; + + out[i + zeros_on_left] = d_constellation[bits]; + i++; + + /* + printf("mod bit: %x out: %.4f + j%.4f resid: %x nresid: %d bit_offset: %d\n", + bits, out[i-1 + zeros_on_left].real(), out[i-1 + zeros_on_left].imag(), + d_resid, d_nresid, d_bit_offset); + */ + } + else { + unsigned int extra = 8-d_bit_offset; + d_resid = ((1 << extra)-1) & (d_msgbytes >> d_bit_offset); + d_bit_offset += extra; + d_nresid = d_nbits - extra; + } + + } + + if(d_bit_offset == 8) { + d_bit_offset = 0; + d_msg_offset++; + } + } + + // Ran out of data to put in symbol + if (d_msg_offset == d_msg->length()) { + if(d_nresid > 0) { + d_resid |= 0x00; + bits = d_resid; + d_nresid = 0; + d_resid = 0; + } + + while(i < d_occupied_carriers) { // finish filling out the symbol + out[i + zeros_on_left] = d_constellation[randsym()]; + i++; + } + + if (d_msg->type() == 1) // type == 1 sets EOF + d_eof = true; + d_msg.reset(); // finished packet, free message + assert(d_bit_offset == 0); + } + + if (out_flag) + out_flag[0] = d_pending_flag; + d_pending_flag = 0; + + return 1; // produced symbol +} diff --git a/gnuradio-core/src/lib/general/gr_ofdm_mapper_bcv.h b/gnuradio-core/src/lib/general/gr_ofdm_mapper_bcv.h index 7b55d90c..a9b676a3 100644 --- a/gnuradio-core/src/lib/general/gr_ofdm_mapper_bcv.h +++ b/gnuradio-core/src/lib/general/gr_ofdm_mapper_bcv.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2006 Free Software Foundation, Inc. + * Copyright 2006,2007 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -23,14 +23,16 @@ #ifndef INCLUDED_GR_OFDM_MAPPER_BCV_H #define INCLUDED_GR_OFDM_MAPPER_BCV_H -#include +#include +#include +#include class gr_ofdm_mapper_bcv; typedef boost::shared_ptr gr_ofdm_mapper_bcv_sptr; gr_ofdm_mapper_bcv_sptr -gr_make_ofdm_mapper_bcv (unsigned int bits_per_symbol, unsigned int vlen); - +gr_make_ofdm_mapper_bcv (const std::vector &constellation, unsigned msgq_limit, + unsigned occupied_carriers, unsigned int fft_length); /*! * \brief take a stream of bytes in and map to a vector of complex @@ -39,18 +41,44 @@ gr_make_ofdm_mapper_bcv (unsigned int bits_per_symbol, unsigned int vlen); * */ -class gr_ofdm_mapper_bcv : public gr_sync_decimator +class gr_ofdm_mapper_bcv : public gr_sync_block { friend gr_ofdm_mapper_bcv_sptr - gr_make_ofdm_mapper_bcv (unsigned int bits_per_symbol, unsigned int vlen); + gr_make_ofdm_mapper_bcv (const std::vector &constellation, unsigned msgq_limit, + unsigned occupied_carriers, unsigned int fft_length); + protected: + gr_ofdm_mapper_bcv (const std::vector &constellation, unsigned msgq_limit, + unsigned occupied_carriers, unsigned int fft_length); + + private: + std::vector d_constellation; + gr_msg_queue_sptr d_msgq; + gr_message_sptr d_msg; + unsigned d_msg_offset; + bool d_eof; + + unsigned int d_occupied_carriers; + unsigned int d_fft_length; + unsigned int d_bit_offset; + int d_pending_flag; + + unsigned long d_nbits; + unsigned char d_msgbytes; + + unsigned char d_resid; + unsigned int d_nresid; -protected: - gr_ofdm_mapper_bcv (unsigned int bits_per_symbol, unsigned int vlen); + int randsym(); -public: + public: ~gr_ofdm_mapper_bcv(void); -}; + gr_msg_queue_sptr msgq() const { return d_msgq; } + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; #endif diff --git a/gnuradio-core/src/lib/general/gr_ofdm_mapper_bcv.i b/gnuradio-core/src/lib/general/gr_ofdm_mapper_bcv.i index e786c70f..30c69292 100644 --- a/gnuradio-core/src/lib/general/gr_ofdm_mapper_bcv.i +++ b/gnuradio-core/src/lib/general/gr_ofdm_mapper_bcv.i @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004,2006 Free Software Foundation, Inc. + * Copyright 2006,2007 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -20,17 +20,27 @@ * Boston, MA 02110-1301, USA. */ -GR_SWIG_BLOCK_MAGIC(gr,ofdm_mapper_bcv) +GR_SWIG_BLOCK_MAGIC(gr,ofdm_mapper_bcv); gr_ofdm_mapper_bcv_sptr -gr_make_ofdm_mapper_bcv (unsigned int bits_per_symbol, - unsigned int vlen); +gr_make_ofdm_mapper_bcv (const std::vector &constellation, + unsigned int msgq_limit, + unsigned int bits_per_symbol, + unsigned int fft_length); -class gr_ofdm_mapper_bcv : public gr_sync_decimator + +class gr_ofdm_mapper_bcv : public gr_sync_block { protected: - gr_ofdm_mapper_bcv (unsigned int bits_per_symbol, - unsigned int vlen); - + gr_ofdm_mapper_bcv (const std::vector &constellation, + unsigned int msgq_limit, + unsigned int bits_per_symbol, + unsigned int fft_length); + public: + gr_msg_queue_sptr msgq(); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); }; diff --git a/gnuradio-core/src/lib/general/gr_ofdm_qpsk_mapper.cc b/gnuradio-core/src/lib/general/gr_ofdm_qpsk_mapper.cc index 011d15f6..39c5bbde 100644 --- a/gnuradio-core/src/lib/general/gr_ofdm_qpsk_mapper.cc +++ b/gnuradio-core/src/lib/general/gr_ofdm_qpsk_mapper.cc @@ -60,7 +60,7 @@ randombit() { int r1 = rand()&1; int r2 = rand()&1; - return gr_complex((0.707)*(-1 + 2*r1),(0.707)*(-1 + 2*r2)); + return gr_complex((0.707)*(1 - 2*r1),(0.707)*(1 - 2*r2)); } int @@ -111,7 +111,7 @@ gr_ofdm_qpsk_mapper::work(int noutput_items, unsigned char bit1 = (d_msg->msg()[d_msg_offset] >> (d_bit_offset)) & 0x01; d_bit_offset++; - out[i + zeros_on_left] = gr_complex((0.707)*(-1+2*(bit0)), (0.707)*(-1+2*(bit1)) ); + out[i + zeros_on_left] = gr_complex((0.707)*(1-2*(bit0)), (0.707)*(1-2*(bit1)) ); i++; if(d_bit_offset == 8) { d_bit_offset = 0; diff --git a/gnuradio-core/src/lib/general/gr_ofdm_sampler.cc b/gnuradio-core/src/lib/general/gr_ofdm_sampler.cc index 02897bb6..56b5d50a 100644 --- a/gnuradio-core/src/lib/general/gr_ofdm_sampler.cc +++ b/gnuradio-core/src/lib/general/gr_ofdm_sampler.cc @@ -69,11 +69,12 @@ gr_ofdm_sampler::general_work (int noutput_items, int i=d_fft_length-1; - while(!found && i= 0); @@ -89,6 +90,5 @@ gr_ofdm_sampler::general_work (int noutput_items, // ninput_items[0], ninput_items[1], noutput_items, (i-d_fft_length+1), found); } - return found; } diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/ofdm.py b/gnuradio-core/src/python/gnuradio/blksimpl/ofdm.py index d4fef81e..b040d8c7 100644 --- a/gnuradio-core/src/python/gnuradio/blksimpl/ofdm.py +++ b/gnuradio-core/src/python/gnuradio/blksimpl/ofdm.py @@ -24,6 +24,7 @@ import math from numpy import fft from gnuradio import gr, ofdm_packet_utils import gnuradio.gr.gr_threading as _threading +import psk, qam from gnuradio.blksimpl.ofdm_receiver import ofdm_receiver @@ -81,15 +82,21 @@ class ofdm_mod(gr.hier_block): padded_preambles.append(padded) symbol_length = options.fft_length + options.cp_length - - # The next step will all us to pass a constellation into a generic mapper function instead - # of using these hard-coded versions - if self._modulation == "bpsk": - self._pkt_input = gr.ofdm_bpsk_mapper(msgq_limit, options.occupied_tones, options.fft_length) - elif self._modulation == "qpsk": - self._pkt_input = gr.ofdm_qpsk_mapper(msgq_limit, options.occupied_tones, options.fft_length) - else: - print "Modulation type not supported (must be \"bpsk\" or \"qpsk\"" + + mods = {"bpsk": 2, "qpsk": 4, "8psk": 8, "qam8": 8, "qam16": 16, "qam64": 64, "qam256": 256} + arity = mods[self._modulation] + + rot = 1 + if self._modulation == "qpsk": + rot = (0.707+0.707j) + + if(self._modulation.find("psk") >= 0): + rotated_const = map(lambda pt: pt * rot, psk.gray_constellation[arity]) + elif(self._modulation.find("qam") >= 0): + rotated_const = map(lambda pt: pt * rot, qam.constellation[arity]) + #print rotated_const + self._pkt_input = gr.ofdm_mapper_bcv(rotated_const, msgq_limit, + options.occupied_tones, options.fft_length) self.preambles = gr.ofdm_insert_preamble(self._fft_length, padded_preambles) self.ifft = gr.fft_vcc(self._fft_length, False, win, True) @@ -104,7 +111,8 @@ class ofdm_mod(gr.hier_block): self._print_verbage() if options.log: - fg.connect(self._pkt_input, gr.file_sink(gr.sizeof_gr_complex*options.fft_length, "ofdm_mapper_c.dat")) + fg.connect(self._pkt_input, gr.file_sink(gr.sizeof_gr_complex*options.fft_length, + "ofdm_mapper_c.dat")) gr.hier_block.__init__(self, fg, None, self.scale) @@ -119,8 +127,8 @@ class ofdm_mod(gr.hier_block): msg = gr.message(1) # tell self._pkt_input we're not sending any more packets else: # print "original_payload =", string_to_hex_list(payload) - pkt = ofdm_packet_utils.make_packet(payload, 1, 1, self._pad_for_usrp) - + pkt = ofdm_packet_utils.make_packet(payload, 1, 1, self._pad_for_usrp, whitening=True) + #print "pkt =", string_to_hex_list(pkt) msg = gr.message_from_string(pkt) self._pkt_input.msgq().insert_tail(msg) @@ -208,9 +216,22 @@ class ofdm_demod(gr.hier_block): self.ofdm_recv = ofdm_receiver(fg, self._fft_length, self._cp_length, self._occupied_tones, self._snr, preambles, options.log) - self.ofdm_demod = gr.ofdm_frame_sink(self._rcvd_pktq, - self._occupied_tones, - self._modulation) + + mods = {"bpsk": 2, "qpsk": 4, "8psk": 8, "qam8": 8, "qam16": 16, "qam64": 64, "qam256": 256} + arity = mods[self._modulation] + + rot = 1 + if self._modulation == "qpsk": + rot = (0.707+0.707j) + + if(self._modulation.find("psk") >= 0): + rotated_const = map(lambda pt: pt * rot, psk.gray_constellation[arity]) + elif(self._modulation.find("qam") >= 0): + rotated_const = map(lambda pt: pt * rot, qam.constellation[arity]) + #print rotated_const + self.ofdm_demod = gr.ofdm_frame_sink(rotated_const, range(arity), + self._rcvd_pktq, + self._occupied_tones) fg.connect((self.ofdm_recv, 0), (self.ofdm_demod, 0)) fg.connect((self.ofdm_recv, 1), (self.ofdm_demod, 1)) diff --git a/gnuradio-core/src/python/gnuradio/blksimpl/psk.py b/gnuradio-core/src/python/gnuradio/blksimpl/psk.py index 5dcf4935..acedf3b6 100644 --- a/gnuradio-core/src/python/gnuradio/blksimpl/psk.py +++ b/gnuradio-core/src/python/gnuradio/blksimpl/psk.py @@ -53,6 +53,12 @@ constellation = { 8 : make_constellation(8) # 8PSK } +gray_constellation = { + 2 : make_gray_constellation(2), # BPSK + 4 : make_gray_constellation(4), # QPSK + 8 : make_gray_constellation(8) # 8PSK + } + # ----------------------- # Do Gray code # ----------------------- diff --git a/gnuradio-core/src/python/gnuradio/gruimpl/crc.py b/gnuradio-core/src/python/gnuradio/gruimpl/crc.py index ad8ce887..d31aca0e 100644 --- a/gnuradio-core/src/python/gnuradio/gruimpl/crc.py +++ b/gnuradio-core/src/python/gnuradio/gruimpl/crc.py @@ -1,5 +1,5 @@ # -# Copyright 2005 Free Software Foundation, Inc. +# Copyright 2005,2007 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -25,7 +25,7 @@ import struct def gen_and_append_crc32(s): crc = gr.crc32(s) - return s + struct.pack(">I", hexint(crc)) + return s + struct.pack(">I", hexint(crc) & 0xFFFFFFFF) def check_crc32(s): if len(s) < 4: diff --git a/gnuradio-examples/python/ofdm/benchmark_ofdm.py b/gnuradio-examples/python/ofdm/benchmark_ofdm.py index 77802540..690c57d6 100755 --- a/gnuradio-examples/python/ofdm/benchmark_ofdm.py +++ b/gnuradio-examples/python/ofdm/benchmark_ofdm.py @@ -36,14 +36,15 @@ class my_graph(gr.flow_graph): def __init__(self, callback, options): gr.flow_graph.__init__(self) - if options.channel_on: + if not options.channel_off: SNR = 10.0**(options.snr/10.0) - power_in_signal = 1.0 + power_in_signal = abs(options.tx_amplitude)**2.0 noise_power_in_channel = power_in_signal/SNR noise_voltage = math.sqrt(noise_power_in_channel/2.0) print "Noise voltage: ", noise_voltage frequency_offset = options.frequency_offset / options.fft_length + print "Frequency offset: ", frequency_offset if options.multipath_on: taps = [1.0, .2, 0.0, .1, .08, -.4, .12, -.2, 0, 0, 0, .3] @@ -70,7 +71,8 @@ class my_graph(gr.flow_graph): self.mux = gr.stream_mux(gr.sizeof_gr_complex, stream_size) self.throttle = gr.throttle(gr.sizeof_gr_complex, options.sample_rate) - self.channel = blks.channel_model(self, noise_voltage, frequency_offset, options.clockrate_ratio, taps) + self.channel = blks.channel_model(self, noise_voltage, frequency_offset, + options.clockrate_ratio, taps) self.rxpath = receive_path(self, callback, options) self.connect(self.zeros, (self.mux,0)) @@ -116,7 +118,7 @@ def main(): parser = OptionParser(option_class=eng_option, conflict_handler="resolve") expert_grp = parser.add_option_group("Expert") - parser.add_option("-s", "--size", type="eng_float", default=1450, + parser.add_option("-s", "--size", type="eng_float", default=400, help="set packet size [default=%default]") parser.add_option("-M", "--megabytes", type="eng_float", default=1.0, help="set megabytes to transmit [default=%default]") @@ -130,8 +132,8 @@ def main(): help="set clock rate ratio (sample rate difference) between two systems [default=%default]") parser.add_option("","--discontinuous", type="int", default=0, help="enable discontinous transmission, burst of N packets [Default is continuous]") - parser.add_option("","--channel-on", action="store_true", default=True, - help="Enables AWGN, freq offset") + parser.add_option("","--channel-off", action="store_true", default=False, + help="Turns AWGN, freq offset channel off") parser.add_option("","--multipath-on", action="store_true", default=False, help="enable multipath") diff --git a/gnuradio-examples/python/ofdm/benchmark_ofdm_rx.py b/gnuradio-examples/python/ofdm/benchmark_ofdm_rx.py index 3e033af4..a8c20d39 100755 --- a/gnuradio-examples/python/ofdm/benchmark_ofdm_rx.py +++ b/gnuradio-examples/python/ofdm/benchmark_ofdm_rx.py @@ -128,7 +128,7 @@ class usrp_graph(gr.flow_graph): expert.add_option("", "--rx-freq", type="eng_float", default=None, help="set Rx frequency to FREQ [default=%default]", metavar="FREQ") - expert.add_option("-d", "--decim", type="intx", default=32, + expert.add_option("-d", "--decim", type="intx", default=128, help="set fpga decimation rate to DECIM [default=%default]") expert.add_option("", "--snr", type="eng_float", default=30, help="set the SNR of the channel in dB [default=%default]") diff --git a/gnuradio-examples/python/ofdm/benchmark_ofdm_tx.py b/gnuradio-examples/python/ofdm/benchmark_ofdm_tx.py index ac7bc0bc..a9d1e00e 100755 --- a/gnuradio-examples/python/ofdm/benchmark_ofdm_tx.py +++ b/gnuradio-examples/python/ofdm/benchmark_ofdm_tx.py @@ -131,7 +131,7 @@ class usrp_graph(gr.flow_graph): expert.add_option("", "--tx-freq", type="eng_float", default=None, help="set transmit frequency to FREQ [default=%default]", metavar="FREQ") - expert.add_option("-i", "--interp", type="intx", default=64, + expert.add_option("-i", "--interp", type="intx", default=256, help="set fpga interpolation rate to INTERP [default=%default]") # Make a static method to call before instantiation add_options = staticmethod(add_options) @@ -171,7 +171,7 @@ def main(): parser = OptionParser(option_class=eng_option, conflict_handler="resolve") expert_grp = parser.add_option_group("Expert") - parser.add_option("-s", "--size", type="eng_float", default=1450, + parser.add_option("-s", "--size", type="eng_float", default=400, help="set packet size [default=%default]") parser.add_option("-M", "--megabytes", type="eng_float", default=1.0, help="set megabytes to transmit [default=%default]") diff --git a/gnuradio-examples/python/ofdm/receive_path.py b/gnuradio-examples/python/ofdm/receive_path.py index 93e1e59a..2ebaad88 100644 --- a/gnuradio-examples/python/ofdm/receive_path.py +++ b/gnuradio-examples/python/ofdm/receive_path.py @@ -47,10 +47,10 @@ class receive_path(gr.hier_block): blks.ofdm_demod(fg, options, callback=self._rx_callback) # Carrier Sensing Blocks - #alpha = 0.001 - #thresh = 30 # in dB, will have to adjust - #self.probe = gr.probe_avg_mag_sqrd_c(thresh,alpha) - #fg.connect(self.chan_filt, self.probe) + alpha = 0.001 + thresh = 30 # in dB, will have to adjust + self.probe = gr.probe_avg_mag_sqrd_c(thresh,alpha) + fg.connect(self.ofdm_rx.ofdm_recv.chan_filt, self.probe) # Display some information about the setup if self._verbose: diff --git a/gnuradio-examples/python/ofdm/transmit_path.py b/gnuradio-examples/python/ofdm/transmit_path.py index 080aee92..f15845b0 100644 --- a/gnuradio-examples/python/ofdm/transmit_path.py +++ b/gnuradio-examples/python/ofdm/transmit_path.py @@ -73,7 +73,7 @@ class transmit_path(gr.hier_block): """ Adds transmitter-specific options to the Options Parser """ - normal.add_option("", "--tx-amplitude", type="eng_float", default=1, metavar="AMPL", + normal.add_option("", "--tx-amplitude", type="eng_float", default=200, metavar="AMPL", help="set transmitter digital amplitude: 0 <= AMPL < 32768 [default=%default]") normal.add_option("-v", "--verbose", action="store_true", default=False) expert.add_option("", "--log", action="store_true", default=False, diff --git a/gnuradio-examples/python/ofdm/tunnel.py b/gnuradio-examples/python/ofdm/tunnel.py new file mode 100755 index 00000000..5babd328 --- /dev/null +++ b/gnuradio-examples/python/ofdm/tunnel.py @@ -0,0 +1,435 @@ +#!/usr/bin/env python +# +# Copyright 2005,2006 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 2, 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. +# + + +# ///////////////////////////////////////////////////////////////////////////// +# +# This code sets up up a virtual ethernet interface (typically gr0), +# and relays packets between the interface and the GNU Radio PHY+MAC +# +# What this means in plain language, is that if you've got a couple +# of USRPs on different machines, and if you run this code on those +# machines, you can talk between them using normal TCP/IP networking. +# +# ///////////////////////////////////////////////////////////////////////////// + + +from gnuradio import gr, gru, blks +from gnuradio import usrp +from gnuradio import eng_notation +from gnuradio.eng_option import eng_option +from optparse import OptionParser + +import random +import time +import struct +import sys +import os + +# from current dir +from transmit_path import transmit_path +from receive_path import receive_path +import fusb_options + +#print os.getpid() +#raw_input('Attach and press enter') + + +# ///////////////////////////////////////////////////////////////////////////// +# +# Use the Universal TUN/TAP device driver to move packets to/from kernel +# +# See /usr/src/linux/Documentation/networking/tuntap.txt +# +# ///////////////////////////////////////////////////////////////////////////// + +# Linux specific... +# TUNSETIFF ifr flags from + +IFF_TUN = 0x0001 # tunnel IP packets +IFF_TAP = 0x0002 # tunnel ethernet frames +IFF_NO_PI = 0x1000 # don't pass extra packet info +IFF_ONE_QUEUE = 0x2000 # beats me ;) + +def open_tun_interface(tun_device_filename): + from fcntl import ioctl + + mode = IFF_TAP | IFF_NO_PI + TUNSETIFF = 0x400454ca + + tun = os.open(tun_device_filename, os.O_RDWR) + ifs = ioctl(tun, TUNSETIFF, struct.pack("16sH", "gr%d", mode)) + ifname = ifs[:16].strip("\x00") + return (tun, ifname) + + +# ///////////////////////////////////////////////////////////////////////////// +# the flow graph +# ///////////////////////////////////////////////////////////////////////////// + +class usrp_graph(gr.flow_graph): + def __init__(self, callback, options): + gr.flow_graph.__init__(self) + + self._tx_freq = options.tx_freq # tranmitter's center frequency + self._tx_subdev_spec = options.tx_subdev_spec # daughterboard to use + self._interp = options.interp # interpolating rate for the USRP (prelim) + self._rx_freq = options.rx_freq # receiver's center frequency + self._rx_gain = options.rx_gain # receiver's gain + self._rx_subdev_spec = options.rx_subdev_spec # daughterboard to use + self._decim = options.decim # Decimating rate for the USRP (prelim) + self._fusb_block_size = options.fusb_block_size # usb info for USRP + self._fusb_nblocks = options.fusb_nblocks # usb info for USRP + + if self._tx_freq is None: + sys.stderr.write("-f FREQ or --freq FREQ or --tx-freq FREQ must be specified\n") + raise SystemExit + + if self._rx_freq is None: + sys.stderr.write("-f FREQ or --freq FREQ or --rx-freq FREQ must be specified\n") + raise SystemExit + + # Set up USRP sink and source + self._setup_usrp_sink() + self._setup_usrp_source() + + # Set center frequency of USRP + ok = self.set_freq(self._tx_freq) + if not ok: + print "Failed to set Tx frequency to %s" % (eng_notation.num_to_str(self._tx_freq),) + raise ValueError + + # copy the final answers back into options for use by modulator + #options.bitrate = self._bitrate + + self.txpath = transmit_path(self, options) + self.rxpath = receive_path(self, callback, options) + + self.connect(self.txpath, self.u_snk) + self.connect(self.u_src, self.rxpath) + + def carrier_sensed(self): + """ + Return True if the receive path thinks there's carrier + """ + return self.rxpath.carrier_sensed() + + def _setup_usrp_sink(self): + """ + Creates a USRP sink, determines the settings for best bitrate, + and attaches to the transmitter's subdevice. + """ + self.u_snk = usrp.sink_c(fusb_block_size=self._fusb_block_size, + fusb_nblocks=self._fusb_nblocks) + + self.u_snk.set_interp_rate(self._interp) + + # determine the daughterboard subdevice we're using + if self._tx_subdev_spec is None: + self._tx_subdev_spec = usrp.pick_tx_subdevice(self.u_snk) + self.u_snk.set_mux(usrp.determine_tx_mux_value(self.u_snk, self._tx_subdev_spec)) + self.subdev = usrp.selected_subdev(self.u_snk, self._tx_subdev_spec) + + # Set the USRP for maximum transmit gain + # (Note that on the RFX cards this is a nop.) + self.set_gain(self.subdev.gain_range()[1]) + + # enable Auto Transmit/Receive switching + self.set_auto_tr(True) + + def _setup_usrp_source(self): + self.u_src = usrp.source_c (fusb_block_size=self._fusb_block_size, + fusb_nblocks=self._fusb_nblocks) + adc_rate = self.u_src.adc_rate() + + self.u_src.set_decim_rate(self._decim) + + # determine the daughterboard subdevice we're using + if self._rx_subdev_spec is None: + self._rx_subdev_spec = usrp.pick_rx_subdevice(self.u_src) + self.subdev = usrp.selected_subdev(self.u_src, self._rx_subdev_spec) + + self.u_src.set_mux(usrp.determine_rx_mux_value(self.u_src, self._rx_subdev_spec)) + + def set_freq(self, target_freq): + """ + Set the center frequency we're interested in. + + @param target_freq: frequency in Hz + @rypte: bool + + Tuning is a two step process. First we ask the front-end to + tune as close to the desired frequency as it can. Then we use + the result of that operation and our target_frequency to + determine the value for the digital up converter. + """ + r_snk = self.u_snk.tune(self.subdev._which, self.subdev, target_freq) + r_src = self.u_src.tune(self.subdev._which, self.subdev, target_freq) + if r_snk and r_src: + return True + + return False + + def set_gain(self, gain): + """ + Sets the analog gain in the USRP + """ + self.gain = gain + self.subdev.set_gain(gain) + + def set_auto_tr(self, enable): + """ + Turns on auto transmit/receive of USRP daughterboard (if exits; else ignored) + """ + return self.subdev.set_auto_tr(enable) + + def interp(self): + return self._interp + + def add_options(normal, expert): + """ + Adds usrp-specific options to the Options Parser + """ + add_freq_option(normal) + normal.add_option("-T", "--tx-subdev-spec", type="subdev", default=None, + help="select USRP Tx side A or B") + normal.add_option("-v", "--verbose", action="store_true", default=False) + + expert.add_option("", "--tx-freq", type="eng_float", default=None, + help="set transmit frequency to FREQ [default=%default]", metavar="FREQ") + expert.add_option("-i", "--interp", type="intx", default=256, + help="set fpga interpolation rate to INTERP [default=%default]") + normal.add_option("-R", "--rx-subdev-spec", type="subdev", default=None, + help="select USRP Rx side A or B") + normal.add_option("", "--rx-gain", type="eng_float", default=None, metavar="GAIN", + help="set receiver gain in dB [default=midpoint]. See also --show-rx-gain-range") + normal.add_option("", "--show-rx-gain-range", action="store_true", default=False, + help="print min and max Rx gain available on selected daughterboard") + normal.add_option("-v", "--verbose", action="store_true", default=False) + + expert.add_option("", "--rx-freq", type="eng_float", default=None, + help="set Rx frequency to FREQ [default=%default]", metavar="FREQ") + expert.add_option("-d", "--decim", type="intx", default=128, + help="set fpga decimation rate to DECIM [default=%default]") + expert.add_option("", "--snr", type="eng_float", default=30, + help="set the SNR of the channel in dB [default=%default]") + + # Make a static method to call before instantiation + add_options = staticmethod(add_options) + + def _print_verbage(self): + """ + Prints information about the transmit path + """ + print "Using TX d'board %s" % (self.subdev.side_and_name(),) + print "modulation: %s" % (self._modulator_class.__name__) + print "interp: %3d" % (self._interp) + print "Tx Frequency: %s" % (eng_notation.num_to_str(self._tx_freq)) + +def add_freq_option(parser): + """ + Hackery that has the -f / --freq option set both tx_freq and rx_freq + """ + def freq_callback(option, opt_str, value, parser): + parser.values.rx_freq = value + parser.values.tx_freq = value + + if not parser.has_option('--freq'): + parser.add_option('-f', '--freq', type="eng_float", + action="callback", callback=freq_callback, + help="set Tx and/or Rx frequency to FREQ [default=%default]", + metavar="FREQ") + + +# ///////////////////////////////////////////////////////////////////////////// +# Carrier Sense MAC +# ///////////////////////////////////////////////////////////////////////////// + +class cs_mac(object): + """ + Prototype carrier sense MAC + + Reads packets from the TUN/TAP interface, and sends them to the PHY. + Receives packets from the PHY via phy_rx_callback, and sends them + into the TUN/TAP interface. + + Of course, we're not restricted to getting packets via TUN/TAP, this + is just an example. + """ + def __init__(self, tun_fd, verbose=False): + self.tun_fd = tun_fd # file descriptor for TUN/TAP interface + self.verbose = verbose + self.fg = None # flow graph (access to PHY) + + def set_flow_graph(self, fg): + self.fg = fg + + def phy_rx_callback(self, ok, payload): + """ + Invoked by thread associated with PHY to pass received packet up. + + @param ok: bool indicating whether payload CRC was OK + @param payload: contents of the packet (string) + """ + if self.verbose: + print "Rx: ok = %r len(payload) = %4d" % (ok, len(payload)) + if ok: + os.write(self.tun_fd, payload) + + def main_loop(self): + """ + Main loop for MAC. + Only returns if we get an error reading from TUN. + + FIXME: may want to check for EINTR and EAGAIN and reissue read + """ + min_delay = 0.001 # seconds + + while 1: + payload = os.read(self.tun_fd, 10*1024) + if not payload: + self.fg.send_pkt(eof=True) + break + + if self.verbose: + print "Tx: len(payload) = %4d" % (len(payload),) + + delay = min_delay + while self.fg.carrier_sensed(): + sys.stderr.write('B') + time.sleep(delay) + if delay < 0.050: + delay = delay * 2 # exponential back-off + + self.fg.send_pkt(payload) + + +# ///////////////////////////////////////////////////////////////////////////// +# main +# ///////////////////////////////////////////////////////////////////////////// + +def main(): + + parser = OptionParser (option_class=eng_option, conflict_handler="resolve") + expert_grp = parser.add_option_group("Expert") + + parser.add_option("-m", "--modulation", type="choice", choices=['bpsk', 'qpsk'], + default='bpsk', + help="Select modulation from: bpsk, qpsk [default=%%default]") + + parser.add_option("-v","--verbose", action="store_true", default=False) + expert_grp.add_option("-c", "--carrier-threshold", type="eng_float", default=30, + help="set carrier detect threshold (dB) [default=%default]") + expert_grp.add_option("","--tun-device-filename", default="/dev/net/tun", + help="path to tun device file [default=%default]") + + usrp_graph.add_options(parser, expert_grp) + transmit_path.add_options(parser, expert_grp) + receive_path.add_options(parser, expert_grp) + blks.ofdm_mod.add_options(parser, expert_grp) + blks.ofdm_demod.add_options(parser, expert_grp) + + fusb_options.add_options(expert_grp) + + (options, args) = parser.parse_args () + if len(args) != 0: + parser.print_help(sys.stderr) + sys.exit(1) + + if options.rx_freq is None or options.tx_freq is None: + sys.stderr.write("You must specify -f FREQ or --freq FREQ\n") + parser.print_help(sys.stderr) + sys.exit(1) + + # open the TUN/TAP interface + (tun_fd, tun_ifname) = open_tun_interface(options.tun_device_filename) + + # Attempt to enable realtime scheduling + r = gr.enable_realtime_scheduling() + if r == gr.RT_OK: + realtime = True + else: + realtime = False + print "Note: failed to enable realtime scheduling" + + + # If the user hasn't set the fusb_* parameters on the command line, + # pick some values that will reduce latency. + + if options.fusb_block_size == 0 and options.fusb_nblocks == 0: + if realtime: # be more aggressive + options.fusb_block_size = gr.prefs().get_long('fusb', 'rt_block_size', 1024) + options.fusb_nblocks = gr.prefs().get_long('fusb', 'rt_nblocks', 16) + else: + options.fusb_block_size = gr.prefs().get_long('fusb', 'block_size', 4096) + options.fusb_nblocks = gr.prefs().get_long('fusb', 'nblocks', 16) + + #print "fusb_block_size =", options.fusb_block_size + #print "fusb_nblocks =", options.fusb_nblocks + + # instantiate the MAC + mac = cs_mac(tun_fd, verbose=True) + + + # build the graph (PHY) + fg = usrp_graph(mac.phy_rx_callback, options) + + mac.set_flow_graph(fg) # give the MAC a handle for the PHY + + #if fg.txpath.bitrate() != fg.rxpath.bitrate(): + # print "WARNING: Transmit bitrate = %sb/sec, Receive bitrate = %sb/sec" % ( + # eng_notation.num_to_str(fg.txpath.bitrate()), + # eng_notation.num_to_str(fg.rxpath.bitrate())) + + print "modulation: %s" % (options.modulation,) + print "freq: %s" % (eng_notation.num_to_str(options.tx_freq)) + #print "bitrate: %sb/sec" % (eng_notation.num_to_str(fg.txpath.bitrate()),) + #print "samples/symbol: %3d" % (fg.txpath.samples_per_symbol(),) + #print "interp: %3d" % (fg.txpath.interp(),) + #print "decim: %3d" % (fg.rxpath.decim(),) + + fg.rxpath.set_carrier_threshold(options.carrier_threshold) + print "Carrier sense threshold:", options.carrier_threshold, "dB" + + print + print "Allocated virtual ethernet interface: %s" % (tun_ifname,) + print "You must now use ifconfig to set its IP address. E.g.," + print + print " $ sudo ifconfig %s 192.168.200.1" % (tun_ifname,) + print + print "Be sure to use a different address in the same subnet for each machine." + print + + + fg.start() # Start executing the flow graph (runs in separate threads) + + mac.main_loop() # don't expect this to return... + + fg.stop() # but if it does, tell flow graph to stop. + fg.wait() # wait for it to finish + + +if __name__ == '__main__': + try: + main() + except KeyboardInterrupt: + pass -- 2.30.2