diff --git a/grc/ieee802_11_decode_signal.xml b/grc/ieee802_11_decode_signal.xml deleted file mode 100644 index 9e0cb19..0000000 --- a/grc/ieee802_11_decode_signal.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - WiFi Decode Signal - ieee802_11_decode_signal - IEEE802.11 - import ieee802_11 - ieee802_11.decode_signal($log, $debug) - - - Log - log - False - bool - - - - - - - Debug - debug - False - bool - - - - - - - in - complex - 48 - 1 - - - - out - complex - 48 - 1 - - - - - diff --git a/grc/ieee802_11_equalize_symbols.xml b/grc/ieee802_11_equalize_symbols.xml deleted file mode 100644 index c274f3a..0000000 --- a/grc/ieee802_11_equalize_symbols.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - WiFi Equalize Symbols - ieee802_11_equalize_symbols - IEEE802.11 - import ieee802_11 - ieee802_11.equalize_symbols($algo, $debug) - set_algorithm($algo) - - - Algorithm - algo - ieee802_11.LINEAR_COMB - int - - - - - - - Debug - debug - False - bool - - - - - - - in - complex - 64 - 1 - - - - out - complex - 48 - 1 - - - - diff --git a/grc/ieee802_11_frame_equalizer.xml b/grc/ieee802_11_frame_equalizer.xml new file mode 100644 index 0000000..59b86ee --- /dev/null +++ b/grc/ieee802_11_frame_equalizer.xml @@ -0,0 +1,105 @@ + + + + WiFi Frame Equalizer + ieee802_11_frame_equalizer + IEEE802.11 + import ieee802_11 + ieee802_11.frame_equalizer($algo, $freq, $bw, $log, $debug) + set_algorithm($algo) + set_frequency($freq) + set_bandwidth($bw) + + + Algorithm + algo + ieee802_11.LS + int + + + + + + + + + Frequency + freq + 5.89e9 + real + + + + Bandwidth + bw + 10e6 + real + + + + Log + log + False + bool + + + + + + + Debug + debug + False + bool + + + + + + + in + complex + 64 + 1 + + + + out + byte + 48 + 1 + + + + symbols + message + 1 + + + + + diff --git a/include/ieee802-11/CMakeLists.txt b/include/ieee802-11/CMakeLists.txt index c7e375e..4275ad8 100644 --- a/include/ieee802-11/CMakeLists.txt +++ b/include/ieee802-11/CMakeLists.txt @@ -72,9 +72,8 @@ list(APPEND include_sources chunks_to_symbols.h constellations.h decode_mac.h - decode_signal.h - equalize_symbols.h ether_encap.h + frame_equalizer.h mac.h mapper.h parse_mac.h diff --git a/include/ieee802-11/decode_signal.h b/include/ieee802-11/decode_signal.h deleted file mode 100644 index a0442ec..0000000 --- a/include/ieee802-11/decode_signal.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2013, 2016 Bastian Bloessl - * - * This program 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 of the License, or - * (at your option) any later version. - * - * This program 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 this program. If not, see . - */ -#ifndef INCLUDED_IEEE802_11_DECODE_SIGNAL_H -#define INCLUDED_IEEE802_11_DECODE_SIGNAL_H - -#include -#include - -namespace gr { -namespace ieee802_11 { - -class IEEE802_11_API decode_signal : virtual public block -{ -public: - - typedef boost::shared_ptr sptr; - static sptr make(bool log = false, bool debug = false); - -}; - -} // namespace ieee802_11 -} // namespace gr - -#endif /* INCLUDED_IEEE802_11_DECODE_SIGNAL_H */ - diff --git a/include/ieee802-11/equalize_symbols.h b/include/ieee802-11/frame_equalizer.h similarity index 59% rename from include/ieee802-11/equalize_symbols.h rename to include/ieee802-11/frame_equalizer.h index 31e75ac..45ebbd0 100644 --- a/include/ieee802-11/equalize_symbols.h +++ b/include/ieee802-11/frame_equalizer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2015, 2016 Bastian Bloessl + * Copyright (C) 2016 Bastian Bloessl * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -13,33 +13,39 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . + * */ -#ifndef INCLUDED_IEEE802_11_EQUALIZE_SYMBOLS_H -#define INCLUDED_IEEE802_11_EQUALIZE_SYMBOLS_H + + +#ifndef INCLUDED_IEEE802_11_FRAME_EQUALIZER_H +#define INCLUDED_IEEE802_11_FRAME_EQUALIZER_H #include #include enum Equalizer { - LMS = 0, - LINEAR_COMB = 1, + LS = 0, + LMS = 1, + COMB = 2, + STA = 3, }; namespace gr { namespace ieee802_11 { -class IEEE802_11_API equalize_symbols : virtual public block +class IEEE802_11_API frame_equalizer : virtual public gr::block { + public: - - typedef boost::shared_ptr sptr; - static sptr make(Equalizer algo, bool debug = false); + typedef boost::shared_ptr sptr; + static sptr make(Equalizer algo, double freq, double bw, + bool log, bool debug); virtual void set_algorithm(Equalizer algo) = 0; - + virtual void set_bandwidth(double bw) = 0; + virtual void set_frequency(double freq) = 0; }; -} // namespace ieee802_11 -} // namespace gr - -#endif /* INCLUDED_IEEE802_11_EQUALIZE_SYMBOLS_H*/ +} // namespace ieee802_11 +} // namespace gr +#endif /* INCLUDED_IEEE802_11_FRAME_EQUALIZER_H */ diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 2ce36d4..ef27018 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -97,14 +97,13 @@ list(APPEND gr_ieee802_11_sources chunks_to_symbols_impl.cc constellations_impl.cc decode_mac.cc - decode_signal.cc - equalize_symbols.cc equalizer/base.cc equalizer/comb.cc equalizer/ls.cc equalizer/lms.cc equalizer/sta.cc ether_encap_impl.cc + frame_equalizer_impl.cc mac.cc mapper.cc parse_mac.cc diff --git a/lib/decode_signal.cc b/lib/decode_signal.cc deleted file mode 100644 index 1f47573..0000000 --- a/lib/decode_signal.cc +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright (C) 2013, 2016 Bastian Bloessl - * - * This program 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 of the License, or - * (at your option) any later version. - * - * This program 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 this program. If not, see . - */ -#include -#include -#include "utils.h" - -#include - -using namespace gr::ieee802_11; -using namespace itpp; - - -class decode_signal_impl : public decode_signal { - -public: -decode_signal_impl(bool log, bool debug) : block("decode_signal", - gr::io_signature::make(1, 1, 48 * sizeof(gr_complex)), - gr::io_signature::make(1, 1, 48 * sizeof(gr_complex))), - d_log(log), - d_debug(debug), - d_copy_symbols(0) { - - decoded_bits.set_size(24); - set_relative_rate(1); - set_tag_propagation_policy(block::TPP_DONT); -} - -~decode_signal_impl(){ -} - -int general_work (int noutput_items, gr_vector_int& ninput_items, - gr_vector_const_void_star& input_items, - gr_vector_void_star& output_items) { - - const gr_complex *in = (const gr_complex*)input_items[0]; - gr_complex *out = (gr_complex*)output_items[0]; - - int i = 0; - int o = 0; - - std::vector tags; - const uint64_t nread = nitems_read(0); - - dout << "Decode Signal: input " << ninput_items[0] - << " output " << noutput_items << std::endl; - - while((i < ninput_items[0]) && (o < noutput_items)) { - - get_tags_in_range(tags, 0, nread + i, nread + i + 1, - pmt::string_to_symbol("wifi_start")); - - if(tags.size()) { - for(int n = 0; n < 48; n++) { - bits[n] = -real(in[n]); - } - - deinterleave(); - - decode(); - - if(print_signal()) { - - add_item_tag(0, nitems_written(0) + o, - pmt::string_to_symbol("wifi_start"), - pmt::cons(pmt::from_uint64(d_len), - pmt::from_uint64(d_encoding)), - pmt::string_to_symbol(name())); - } - - } else if(d_copy_symbols) { - - std::memcpy(out, in, 48 * sizeof(gr_complex)); - o++; - out += 48; - d_copy_symbols--; - } - - in += 48; - i++; - } - - dout << "Decode Signal consumed " << i << - " produced " << o << std::endl; - - consume(0, i); - return o; -} - -void deinterleave() { - double tmp[48]; - for(int i = 0; i < 48; i++) { - tmp[i] = bits[inter[i]]; - } - for(int i = 0; i < 48; i++) { - bits[i] = tmp[i]; - } - for(int i = 0; i < 48; i++) { - dout << bits[i] << " "; - } - dout << std::endl; - -} - -void decode() { - - Convolutional_Code code; - ivec generator(2); - generator(0)=0133; - generator(1)=0171; - code.set_generator_polynomials(generator, 7); - code.set_truncation_length(30); - - vec rx_signal(bits, 48); - code.reset(); - code.decode_tail(rx_signal, decoded_bits); - - dout << "length rx " << rx_signal.size() << std::endl; - dout << rx_signal << std::endl; - dout << "length decoded " << decoded_bits.size() << std::endl; - dout << decoded_bits << std::endl; - -} - -bool print_signal() { - - int r = 0; - d_len = 0; - bool parity = false; - for(int i = 0; i < 17; i++) { - parity ^= (bool)decoded_bits[i]; - - if((i < 4) && decoded_bits[i]) { - r = r | (1 << i); - } - - if(decoded_bits[i] && (i > 4) && (i < 17)) { - d_len = d_len | (1 << (i-5)); - } - } - - if(parity != (bool)decoded_bits[17]) { - dout << "SIGNAL: wrong parity" << std::endl; - return false; - } - - if(r == 11) { - d_encoding = 0; - d_copy_symbols = (int) ceil((16 + 8 * d_len + 6) / (double) 24); - dout << "Encoding: 3 Mbit/s "; - } else if(r == 15) { - d_encoding = 1; - d_copy_symbols = (int) ceil((16 + 8 * d_len + 6) / (double) 36); - dout << "Encoding: 4.5 Mbit/s "; - } else if(r == 10) { - d_encoding = 2; - d_copy_symbols = (int) ceil((16 + 8 * d_len + 6) / (double) 48); - dout << "Encoding: 6 Mbit/s "; - } else if(r == 14) { - d_encoding = 3; - d_copy_symbols = (int) ceil((16 + 8 * d_len + 6) / (double) 72); - dout << "Encoding: 9 Mbit/s "; - } else if(r == 9) { - d_encoding = 4; - d_copy_symbols = (int) ceil((16 + 8 * d_len + 6) / (double) 96); - dout << "Encoding: 12 Mbit/s "; - } else if(r == 13) { - d_encoding = 5; - d_copy_symbols = (int) ceil((16 + 8 * d_len + 6) / (double) 144); - dout << "Encoding: 18 Mbit/s "; - } else if(r == 8) { - d_encoding = 6; - d_copy_symbols = (int) ceil((16 + 8 * d_len + 6) / (double) 192); - dout << "Encoding: 24 Mbit/s "; - } else if(r == 12) { - d_encoding = 7; - d_copy_symbols = (int) ceil((16 + 8 * d_len + 6) / (double) 216); - dout << "Encoding: 27 Mbit/s "; - } else { - dout << "unknown encoding" << std::endl; - return false; - } - - mylog(boost::format("encoding: %1% - length: %2% - symbols: %3%") - % d_encoding % d_len % d_copy_symbols); - - dout << "d_copy_symbols: " << d_copy_symbols << std::endl; - dout << "length: " << d_len << std::endl; - return true; -} - -private: - int d_len; - int d_encoding; - bool d_log; - bool d_debug; - double bits[48]; - int d_copy_symbols; - bvec decoded_bits; - static int inter[48]; -}; - -decode_signal::sptr -decode_signal::make(bool log, bool debug) { - return gnuradio::get_initial_sptr(new decode_signal_impl(log, debug)); -} - -int decode_signal_impl::inter[48]={0,3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,1,4,7,10,13,16,19,22,25,28,31,34,37,40,43,46,2,5,8,11,14,17,20,23,26,29,32,35,38,41,44,47}; - diff --git a/lib/equalize_symbols.cc b/lib/equalize_symbols.cc deleted file mode 100644 index 23eae0b..0000000 --- a/lib/equalize_symbols.cc +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2013, 2016 Bastian Bloessl - * - * This program 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 of the License, or - * (at your option) any later version. - * - * This program 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 this program. If not, see . - */ -#include - -#include "utils.h" -#include "equalizer/base.h" -#include "equalizer/linear_comb.h" -#include "equalizer/lms.h" -#include - -using namespace gr::ieee802_11; - - -class equalize_symbols_impl : public equalize_symbols { - -public: -equalize_symbols_impl(Equalizer algo, bool debug) : block("equalize_symbols", - gr::io_signature::make(1, 1, 64 * sizeof(gr_complex)), - gr::io_signature::make(1, 1, 48 * sizeof(gr_complex))), - d_debug(debug), d_equalizer(NULL) { - - set_relative_rate(1); - set_tag_propagation_policy(block::TPP_DONT); - set_algorithm(algo); -} - -~equalize_symbols_impl(){ -} - -int general_work (int noutput_items, gr_vector_int& ninput_items, - gr_vector_const_void_star& input_items, - gr_vector_void_star& output_items) { - - gr::thread::scoped_lock lock(d_mutex); - - const gr_complex *in = (const gr_complex*)input_items[0]; - gr_complex *out = (gr_complex*)output_items[0]; - - int i = 0; - int o = 0; - - dout << "SYMBOLS: input " << ninput_items[0] << " output " << noutput_items << std::endl; - - while((i < ninput_items[0]) && (o < noutput_items)) { - - get_tags_in_window(tags, 0, i, i + 1, pmt::string_to_symbol("wifi_start")); - - // new WiFi frame - if(tags.size()) { - d_nsym = 0; - } - - // first data symbol (= signal field) - if(d_nsym == 2) { - add_item_tag(0, nitems_written(0) + o, - pmt::string_to_symbol("wifi_start"), - pmt::PMT_T, - pmt::string_to_symbol(name())); - } - - d_equalizer->equalize(in + (i * 64), out + (o * 48), d_nsym); - - if(d_nsym > 1) { - o++; - } - i++; - d_nsym++; - } - - dout << "SYMBOLS: consumed " << i << " produced " << o << std::endl; - - consume(0, i); - return o; -} - -void set_algorithm(Equalizer algo) { - gr::thread::scoped_lock lock(d_mutex); - delete d_equalizer; - - switch(algo) { - case LMS: - dout << "LMS" << std::endl; - d_equalizer = new equalizer::lms(); - break; - - case LINEAR_COMB: - dout << "Linear Comb" << std::endl; - d_equalizer = new equalizer::linear_comb(); - break; - } -} - -private: - int d_nsym; - const bool d_debug; - equalizer::base *d_equalizer; - std::vector tags; - gr::thread::mutex d_mutex; -}; - - -equalize_symbols::sptr -equalize_symbols::make(Equalizer algo, bool debug) { - return gnuradio::get_initial_sptr(new equalize_symbols_impl(algo, debug)); -} - diff --git a/lib/frame_equalizer_impl.cc b/lib/frame_equalizer_impl.cc new file mode 100644 index 0000000..1bc8355 --- /dev/null +++ b/lib/frame_equalizer_impl.cc @@ -0,0 +1,344 @@ +/* + * Copyright (C) 2016 Bastian Bloessl + * + * This program 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 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see . + */ + +#include "frame_equalizer_impl.h" +#include "equalizer/base.h" +#include "equalizer/comb.h" +#include "equalizer/lms.h" +#include "equalizer/ls.h" +#include "equalizer/sta.h" +#include "utils.h" +#include + +namespace gr { +namespace ieee802_11 { + +frame_equalizer::sptr +frame_equalizer::make(Equalizer algo, double freq, double bw, bool log, bool debug) { + return gnuradio::get_initial_sptr + (new frame_equalizer_impl(algo, freq, bw, log, debug)); +} + + +frame_equalizer_impl::frame_equalizer_impl(Equalizer algo, double freq, double bw, bool log, bool debug) : + gr::block("frame_equalizer", + gr::io_signature::make(1, 1, 64 * sizeof(gr_complex)), + gr::io_signature::make(1, 1, 48)), + d_current_symbol(0), d_log(log), d_debug(debug), d_equalizer(NULL), + d_freq(freq), d_bw(bw), d_frame_bytes(0), d_frame_symbols(0) { + + message_port_register_out(pmt::mp("symbols")); + + d_bpsk = constellation_bpsk::make(); + d_qpsk = constellation_qpsk::make(); + d_16qam = constellation_16qam::make(); + d_64qam = constellation_64qam::make(); + + d_frame_mod = d_bpsk; + + set_tag_propagation_policy(block::TPP_DONT); + set_algorithm(algo); +} + +frame_equalizer_impl::~frame_equalizer_impl() { +} + + +void +frame_equalizer_impl::set_algorithm(Equalizer algo) { + gr::thread::scoped_lock lock(d_mutex); + delete d_equalizer; + + switch(algo) { + + case COMB: + dout << "Comb" << std::endl; + d_equalizer = new equalizer::comb(); + break; + case LS: + dout << "LS" << std::endl; + d_equalizer = new equalizer::ls(); + break; + case LMS: + dout << "LMS" << std::endl; + d_equalizer = new equalizer::lms(); + break; + case STA: + dout << "Comb" << std::endl; + d_equalizer = new equalizer::sta(); + break; + default: + throw std::runtime_error("Algorithm not implemented"); + } +} + +void +frame_equalizer_impl::set_bandwidth(double bw) { + gr::thread::scoped_lock lock(d_mutex); + d_bw = bw; +} + +void +frame_equalizer_impl::set_frequency(double freq) { + gr::thread::scoped_lock lock(d_mutex); + d_freq = freq; +} + +void +frame_equalizer_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required) { + ninput_items_required[0] = noutput_items; +} + +int +frame_equalizer_impl::general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) { + + gr::thread::scoped_lock lock(d_mutex); + + const gr_complex *in = (const gr_complex *) input_items[0]; + uint8_t *out = (uint8_t *) output_items[0]; + + int i = 0; + int o = 0; + gr_complex symbols[48]; + gr_complex current_symbol[64]; + + dout << "FRAME EQUALIZER: input " << ninput_items[0] << " output " << noutput_items << std::endl; + + while((i < ninput_items[0]) && (o < noutput_items)) { + + get_tags_in_window(tags, 0, i, i + 1, pmt::string_to_symbol("wifi_start")); + + // new frame + if(tags.size()) { + d_current_symbol = 0; + d_frame_symbols = 0; + d_frame_mod = d_bpsk; + + d_epsilon0 = pmt::to_double(tags.front().value) * d_bw / (2 * M_PI * d_freq); + d_er = 0; + + dout << "epsilon: " << d_epsilon0 << std::endl; + } + + // not interesting -> skip + if(d_current_symbol > (d_frame_symbols + 2)) { + i++; + continue; + } + + std::memcpy(current_symbol, in + i*64, 64*sizeof(gr_complex)); + + // compensate sampling offset + for(int i = 0; i < 64; i++) { + current_symbol[i] *= exp(gr_complex(0, 2*M_PI*d_current_symbol*80*(d_epsilon0 + d_er)*(i-32)/64)); + } + + gr_complex p = equalizer::base::POLARITY[(d_current_symbol - 2) % 127]; + gr_complex sum = + (current_symbol[11] * p) + + (current_symbol[25] * p) + + (current_symbol[39] * p) + + (current_symbol[53] * -p); + + double beta; + if(d_current_symbol < 2) { + beta = arg( + current_symbol[11] - + current_symbol[25] + + current_symbol[39] + + current_symbol[53]); + + } else { + beta = arg( + (current_symbol[11] * p) + + (current_symbol[39] * p) + + (current_symbol[25] * p) + + (current_symbol[53] * -p)); + } + + double er = arg( + (conj(d_prev_pilots[0]) * current_symbol[11] * p) + + (conj(d_prev_pilots[1]) * current_symbol[25] * p) + + (conj(d_prev_pilots[2]) * current_symbol[39] * p) + + (conj(d_prev_pilots[3]) * current_symbol[53] * -p)); + + er *= d_bw / (2 * M_PI * d_freq * 80); + + d_prev_pilots[0] = current_symbol[11] * p; + d_prev_pilots[1] = current_symbol[25] * p; + d_prev_pilots[2] = current_symbol[39] * p; + d_prev_pilots[3] = current_symbol[53] * -p; + + // compensate residual frequency offset + for(int i = 0; i < 64; i++) { + current_symbol[i] *= exp(gr_complex(0, -beta)); + } + + // update estimate of residual frequency offset + if(d_current_symbol >= 2) { + + double alpha = 0.1; + d_er = (1-alpha) * d_er + alpha * er; + } + + // do equalization + d_equalizer->equalize(current_symbol, d_current_symbol, + symbols, out + o * 48, d_frame_mod); + + // signal field + if(d_current_symbol == 2) { + + if(decode_signal_field(out + o * 48)) { + + add_item_tag(0, nitems_written(0) + o, + pmt::string_to_symbol("wifi_start"), + pmt::make_tuple(pmt::from_uint64(d_frame_bytes), + pmt::from_uint64(d_frame_encoding), + pmt::from_double(d_equalizer->get_snr())), + pmt::string_to_symbol(name())); + } + } + + if(d_current_symbol > 2) { + o++; + pmt::pmt_t pdu = pmt::make_dict(); + message_port_pub(pmt::mp("symbols"), pmt::cons(pmt::make_dict(), pmt::init_c32vector(48, symbols))); + } + + i++; + d_current_symbol++; + } + + consume(0, i); + return o; +} + +bool +frame_equalizer_impl::decode_signal_field(uint8_t *rx_bits) { + + static ofdm_param ofdm(BPSK_1_2); + static frame_param frame(ofdm, 0); + + deinterleave(rx_bits); + uint8_t *decoded_bits = d_decoder.decode(&ofdm, &frame, d_deinterleaved); + + return parse_signal(decoded_bits); +} + +void +frame_equalizer_impl::deinterleave(uint8_t *rx_bits) { + for(int i = 0; i < 48; i++) { + d_deinterleaved[i] = rx_bits[interleaver_pattern[i]]; + } +} + +bool +frame_equalizer_impl::parse_signal(uint8_t *decoded_bits) { + + int r = 0; + d_frame_bytes = 0; + bool parity = false; + for(int i = 0; i < 17; i++) { + parity ^= decoded_bits[i]; + + if((i < 4) && decoded_bits[i]) { + r = r | (1 << i); + } + + if(decoded_bits[i] && (i > 4) && (i < 17)) { + d_frame_bytes = d_frame_bytes | (1 << (i-5)); + } + } + + if(parity != decoded_bits[17]) { + dout << "SIGNAL: wrong parity" << std::endl; + return false; + } + + switch(r) { + case 11: + d_frame_encoding = 0; + d_frame_symbols = (int) ceil((16 + 8 * d_frame_bytes + 6) / (double) 24); + d_frame_mod = d_bpsk; + dout << "Encoding: 3 Mbit/s "; + break; + case 15: + d_frame_encoding = 1; + d_frame_symbols = (int) ceil((16 + 8 * d_frame_bytes + 6) / (double) 36); + d_frame_mod = d_bpsk; + dout << "Encoding: 4.5 Mbit/s "; + break; + case 10: + d_frame_encoding = 2; + d_frame_symbols = (int) ceil((16 + 8 * d_frame_bytes + 6) / (double) 48); + d_frame_mod = d_qpsk; + dout << "Encoding: 6 Mbit/s "; + break; + case 14: + d_frame_encoding = 3; + d_frame_symbols = (int) ceil((16 + 8 * d_frame_bytes + 6) / (double) 72); + d_frame_mod = d_qpsk; + dout << "Encoding: 9 Mbit/s "; + break; + case 9: + d_frame_encoding = 4; + d_frame_symbols = (int) ceil((16 + 8 * d_frame_bytes + 6) / (double) 96); + d_frame_mod = d_16qam; + dout << "Encoding: 12 Mbit/s "; + break; + case 13: + d_frame_encoding = 5; + d_frame_symbols = (int) ceil((16 + 8 * d_frame_bytes + 6) / (double) 144); + d_frame_mod = d_16qam; + dout << "Encoding: 18 Mbit/s "; + break; + case 8: + d_frame_encoding = 6; + d_frame_symbols = (int) ceil((16 + 8 * d_frame_bytes + 6) / (double) 192); + d_frame_mod = d_64qam; + dout << "Encoding: 24 Mbit/s "; + break; + case 12: + d_frame_encoding = 7; + d_frame_symbols = (int) ceil((16 + 8 * d_frame_bytes + 6) / (double) 216); + d_frame_mod = d_64qam; + dout << "Encoding: 27 Mbit/s "; + break; + defaul: + dout << "unknown encoding" << std::endl; + return false; + } + + mylog(boost::format("encoding: %1% - length: %2% - symbols: %3%") + % d_frame_encoding % d_frame_bytes % d_frame_symbols); + return true; +} + +int +frame_equalizer_impl::interleaver_pattern[48] = { + 0, 3, 6, 9,12,15,18,21, + 24,27,30,33,36,39,42,45, + 1, 4, 7,10,13,16,19,22, + 25,28,31,34,37,40,43,46, + 2, 5, 8,11,14,17,20,23, + 26,29,32,35,38,41,44,47}; + +} /* namespace ieee802_11 */ +} /* namespace gr */ diff --git a/lib/frame_equalizer_impl.h b/lib/frame_equalizer_impl.h new file mode 100644 index 0000000..d7ed540 --- /dev/null +++ b/lib/frame_equalizer_impl.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2016 Bastian Bloessl + * + * This program 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 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see . + */ + +#ifndef INCLUDED_IEEE802_11_FRAME_EQUALIZER_IMPL_H +#define INCLUDED_IEEE802_11_FRAME_EQUALIZER_IMPL_H + +#include +#include +#include "equalizer/base.h" +#include "viterbi_decoder.h" + +namespace gr { +namespace ieee802_11 { + +class frame_equalizer_impl : virtual public frame_equalizer +{ + +public: + frame_equalizer_impl(Equalizer algo, double freq, double bw, bool log, bool debug); + ~frame_equalizer_impl(); + + void set_algorithm(Equalizer algo); + void set_bandwidth(double bw); + void set_frequency(double freq); + + void forecast (int noutput_items, gr_vector_int &ninput_items_required); + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + +private: + + + bool parse_signal(uint8_t *signal); + bool decode_signal_field(uint8_t *rx_bits); + void deinterleave(uint8_t *rx_bits); + + equalizer::base *d_equalizer; + gr::thread::mutex d_mutex; + std::vector tags; + bool d_debug; + bool d_log; + int d_current_symbol; + viterbi_decoder d_decoder; + + // freq offset + double d_freq; + double d_bw; + double d_er; + double d_epsilon0; + gr_complex d_prev_pilots[4]; + + int d_frame_bytes; + int d_frame_symbols; + int d_frame_encoding; + + uint8_t d_deinterleaved[48]; + gr_complex symbols[48]; + + boost::shared_ptr d_frame_mod; + constellation_bpsk::sptr d_bpsk; + constellation_qpsk::sptr d_qpsk; + constellation_16qam::sptr d_16qam; + constellation_64qam::sptr d_64qam; + + static int interleaver_pattern[48]; +}; + +} // namespace ieee802_11 +} // namespace gr + +#endif /* INCLUDED_IEEE802_11_FRAME_EQUALIZER_IMPL_H */ diff --git a/lib/utils.cc b/lib/utils.cc index a50f750..e4dc39e 100644 --- a/lib/utils.cc +++ b/lib/utils.cc @@ -20,62 +20,6 @@ #include #include -// constellations for different modulations (normalized to avg power 1) -const std::complex BPSK_D[2] = { - std::complex(-1.0, 0.0), std::complex(1.0, 0.0)}; - - -const std::complex QPSK_D[4] = { - std::complex(-0.7071, -0.7071), std::complex(-0.7071, 0.7071), - std::complex(+0.7071, -0.7071), std::complex(+0.7071, 0.7071)}; - - -const std::complex QAM16_D[16] = { - std::complex(-0.9487, -0.9487), std::complex(-0.9487, -0.3162), - std::complex(-0.9487, 0.9487), std::complex(-0.9487, 0.3162), - std::complex(-0.3162, -0.9487), std::complex(-0.3162, -0.3162), - std::complex(-0.3162, 0.9487), std::complex(-0.3162, 0.3162), - std::complex(0.9487, -0.9487), std::complex(0.9487, -0.3162), - std::complex(0.9487, 0.9487), std::complex(0.9487, 0.3162), - std::complex(0.3162, -0.9487), std::complex(0.3162, -0.3162), - std::complex(0.3162, 0.9487), std::complex(0.3162, 0.3162)}; - - -const std::complex QAM64_D[64] = { - std::complex(-1.0801, -1.0801), std::complex(-1.0801, -0.7715), - std::complex(-1.0801, -0.1543), std::complex(-1.0801, -0.4629), - std::complex(-1.0801, 1.0801), std::complex(-1.0801, 0.7715), - std::complex(-1.0801, 0.1543), std::complex(-1.0801, 0.4629), - std::complex(-0.7715, -1.0801), std::complex(-0.7715, -0.7715), - std::complex(-0.7715, -0.1543), std::complex(-0.7715, -0.4629), - std::complex(-0.7715, 1.0801), std::complex(-0.7715, 0.7715), - std::complex(-0.7715, 0.1543), std::complex(-0.7715, 0.4629), - std::complex(-0.1543, -1.0801), std::complex(-0.1543, -0.7715), - std::complex(-0.1543, -0.1543), std::complex(-0.1543, -0.4629), - std::complex(-0.1543, 1.0801), std::complex(-0.1543, 0.7715), - std::complex(-0.1543, 0.1543), std::complex(-0.1543, 0.4629), - std::complex(-0.4629, -1.0801), std::complex(-0.4629, -0.7715), - std::complex(-0.4629, -0.1543), std::complex(-0.4629, -0.4629), - std::complex(-0.4629, 1.0801), std::complex(-0.4629, 0.7715), - std::complex(-0.4629, 0.1543), std::complex(-0.4629, 0.4629), - std::complex(1.0801, -1.0801), std::complex(1.0801, -0.7715), - std::complex(1.0801, -0.1543), std::complex(1.0801, -0.4629), - std::complex(1.0801, 1.0801), std::complex(1.0801, 0.7715), - std::complex(1.0801, 0.1543), std::complex(1.0801, 0.4629), - std::complex(0.7715, -1.0801), std::complex(0.7715, -0.7715), - std::complex(0.7715, -0.1543), std::complex(0.7715, -0.4629), - std::complex(0.7715, 1.0801), std::complex(0.7715, 0.7715), - std::complex(0.7715, 0.1543), std::complex(0.7715, 0.4629), - std::complex(0.1543, -1.0801), std::complex(0.1543, -0.7715), - std::complex(0.1543, -0.1543), std::complex(0.1543, -0.4629), - std::complex(0.1543, 1.0801), std::complex(0.1543, 0.7715), - std::complex(0.1543, 0.1543), std::complex(0.1543, 0.4629), - std::complex(0.4629, -1.0801), std::complex(0.4629, -0.7715), - std::complex(0.4629, -0.1543), std::complex(0.4629, -0.4629), - std::complex(0.4629, 1.0801), std::complex(0.4629, 0.7715), - std::complex(0.4629, 0.1543), std::complex(0.4629, 0.4629)}; - - ofdm_param::ofdm_param(Encoding e) { encoding = e; @@ -160,11 +104,10 @@ frame_param::frame_param(ofdm_param &ofdm, int psdu_length) { // number of symbols (17-11) n_sym = (int) ceil((16 + 8 * psdu_size + 6) / (double) ofdm.n_dbps); - // number of bits of the data field (17-12) - n_data = n_sym * ofdm.n_dbps; + n_data_bits = n_sym * ofdm.n_dbps; // number of padding bits (17-13) - n_pad = n_data - (16 + 8 * psdu_size + 6); + n_pad = n_data_bits - (16 + 8 * psdu_size + 6); n_encoded_bits = n_sym * ofdm.n_cbps; } @@ -173,8 +116,9 @@ frame_param::print() { std::cout << "FRAME Parameters:" << std::endl; std::cout << "psdu_size: " << psdu_size << std::endl; std::cout << "n_sym: " << n_sym << std::endl; - std::cout << "n_data: " << n_data << std::endl; std::cout << "n_pad: " << n_pad << std::endl; + std::cout << "n_encoded_bits: " << n_encoded_bits << std::endl; + std::cout << "n_data_bits: " << n_data_bits << std::endl; } @@ -183,7 +127,7 @@ void scramble(const char *in, char *out, frame_param &frame, char initial_state) int state = initial_state; int feedback; - for (int i = 0; i < frame.n_data; i++) { + for (int i = 0; i < frame.n_data_bits; i++) { feedback = (!!(state & 64)) ^ (!!(state & 8)); out[i] = feedback ^ in[i]; @@ -193,7 +137,7 @@ void scramble(const char *in, char *out, frame_param &frame, char initial_state) void reset_tail_bits(char *scrambled_data, frame_param &frame) { - memset(scrambled_data + frame.n_data - frame.n_pad - 6, 0, 6 * sizeof(char)); + memset(scrambled_data + frame.n_data_bits - frame.n_pad - 6, 0, 6 * sizeof(char)); } @@ -212,7 +156,7 @@ void convolutional_encoding(const char *in, char *out, frame_param &frame) { int state = 0; - for(int i = 0; i < frame.n_data; i++) { + for(int i = 0; i < frame.n_data_bits; i++) { assert(in[i] == 0 || in[i] == 1); state = ((state << 1) & 0x7e) | in[i]; out[i * 2] = ones(state & 0155) % 2; @@ -225,7 +169,7 @@ void puncturing(const char *in, char *out, frame_param &frame, ofdm_param &ofdm) int mod; - for (int i = 0; i < frame.n_data * 2; i++) { + for (int i = 0; i < frame.n_data_bits * 2; i++) { switch(ofdm.encoding) { case BPSK_1_2: case QPSK_1_2: @@ -286,33 +230,6 @@ void interleave(const char *in, char *out, frame_param &frame, ofdm_param &ofdm, } -void interleave(const double *in, double *out, frame_param &frame, ofdm_param &ofdm, bool reverse) { - - int n_cbps = ofdm.n_cbps; - int first[n_cbps]; - int second[n_cbps]; - int s = std::max(ofdm.n_bpsc / 2, 1); - - for(int j = 0; j < n_cbps; j++) { - first[j] = s * (j / s) + ((j + int(floor(16.0 * j / n_cbps))) % s); - } - - for(int i = 0; i < n_cbps; i++) { - second[i] = 16 * i - (n_cbps - 1) * int(floor(16.0 * i / n_cbps)); - } - - for(int i = 0; i < frame.n_sym; i++) { - for(int k = 0; k < n_cbps; k++) { - if(reverse) { - out[i * n_cbps + second[first[k]]] = in[i * n_cbps + k]; - } else { - out[i * n_cbps + k] = in[i * n_cbps + second[first[k]]]; - } - } - } -} - - void split_symbols(const char *in, char *out, frame_param &frame, ofdm_param &ofdm) { int symbols = frame.n_sym * 48; @@ -321,7 +238,7 @@ void split_symbols(const char *in, char *out, frame_param &frame, ofdm_param &of out[i] = 0; for(int k = 0; k < ofdm.n_bpsc; k++) { assert(*in == 1 || *in == 0); - out[i] |= (*in << (ofdm.n_bpsc - k - 1)); + out[i] |= (*in << k); in++; } } diff --git a/lib/utils.h b/lib/utils.h index a75a523..2818d85 100644 --- a/lib/utils.h +++ b/lib/utils.h @@ -23,8 +23,9 @@ #include #include -const int MAX_SYM = 520; // enough for 1500 byte BPSK 1/2 -const int MAX_BITS = 1550 * 8 * 2; +#define MAX_FRAME_SIZE (1500 + 28 + 4) +#define MAX_SYM (((16 + 8 * MAX_FRAME_SIZE + 6) / 24) + 1) +#define MAX_ENCODED_BITS ((16 + 8 * MAX_FRAME_SIZE + 6) * 2 + 288) #define dout d_debug && std::cout @@ -34,12 +35,6 @@ const int MAX_BITS = 1550 * 8 * 2; #define mylog(msg) do { d_log && std::cout << msg << std::endl; } while(0); #endif -// same mappings in double (itpp sucks) -extern const std::complex BPSK_D[2]; -extern const std::complex QPSK_D[4]; -extern const std::complex QAM16_D[16]; -extern const std::complex QAM64_D[64]; - struct mac_header { //protocol version, type, subtype, to_ds, from_ds, ... uint16_t frame_control; @@ -81,11 +76,11 @@ public: int psdu_size; // number of OFDM symbols (17-11) int n_sym; - // number of data bits in the DATA field, including service and padding (17-12) - int n_data; // number of padding bits in the DATA field (17-13) int n_pad; int n_encoded_bits; + // number of data bits, including service and padding (17-12) + int n_data_bits; void print(); }; @@ -104,7 +99,6 @@ public: */ void generate_mac_data_frame(const char *msdu, int msdu_size, char **psdu, int *psdu_size, char seq); - void scramble(const char *input, char *out, frame_param &frame, char initial_state); void reset_tail_bits(char *scrambled_data, frame_param &frame); @@ -114,7 +108,6 @@ void convolutional_encoding(const char *input, char *out, frame_param &frame); void puncturing(const char *input, char *out, frame_param &frame, ofdm_param &ofdm); void interleave(const char *input, char *out, frame_param &frame, ofdm_param &ofdm, bool reverse = false); -void interleave(const double *input, double *out, frame_param &frame, ofdm_param &ofdm, bool reverse = false); void split_symbols(const char *input, char *out, frame_param &frame, ofdm_param &ofdm); diff --git a/swig/ieee802_11_swig.i b/swig/ieee802_11_swig.i index 2eba124..905a2f5 100644 --- a/swig/ieee802_11_swig.i +++ b/swig/ieee802_11_swig.i @@ -22,22 +22,19 @@ %include "ieee802_11_swig_doc.i" %{ -#include "gnuradio/digital/packet_header_default.h" - #include "ieee802-11/chunks_to_symbols.h" #include "ieee802-11/constellations.h" -#include "ieee802-11/ether_encap.h" -#include "ieee802-11/moving_average_cc.h" -#include "ieee802-11/moving_average_ff.h" #include "ieee802-11/decode_mac.h" -#include "ieee802-11/decode_signal.h" -#include "ieee802-11/equalize_symbols.h" +#include "ieee802-11/ether_encap.h" +#include "ieee802-11/frame_equalizer.h" #include "ieee802-11/mac.h" #include "ieee802-11/mapper.h" +#include "ieee802-11/moving_average_cc.h" +#include "ieee802-11/moving_average_ff.h" #include "ieee802-11/parse_mac.h" +#include "ieee802-11/signal_field.h" #include "ieee802-11/sync_long.h" #include "ieee802-11/sync_short.h" -#include "ieee802-11/signal_field.h" %} %include "gnuradio/digital/packet_header_default.h" @@ -49,28 +46,26 @@ %include "ieee802-11/chunks_to_symbols.h" %include "ieee802-11/constellations.h" -%include "ieee802-11/ether_encap.h" -%include "ieee802-11/moving_average_cc.h" -%include "ieee802-11/moving_average_ff.h" %include "ieee802-11/decode_mac.h" -%include "ieee802-11/decode_signal.h" -%include "ieee802-11/equalize_symbols.h" +%include "ieee802-11/ether_encap.h" +%include "ieee802-11/frame_equalizer.h" %include "ieee802-11/mac.h" %include "ieee802-11/mapper.h" +%include "ieee802-11/moving_average_cc.h" +%include "ieee802-11/moving_average_ff.h" %include "ieee802-11/parse_mac.h" +%include "ieee802-11/signal_field.h" %include "ieee802-11/sync_long.h" %include "ieee802-11/sync_short.h" -%include "ieee802-11/signal_field.h" GR_SWIG_BLOCK_MAGIC2(ieee802_11, chunks_to_symbols); -GR_SWIG_BLOCK_MAGIC2(ieee802_11, ether_encap); -GR_SWIG_BLOCK_MAGIC2(ieee802_11, moving_average_cc); -GR_SWIG_BLOCK_MAGIC2(ieee802_11, moving_average_ff); GR_SWIG_BLOCK_MAGIC2(ieee802_11, decode_mac); -GR_SWIG_BLOCK_MAGIC2(ieee802_11, decode_signal); -GR_SWIG_BLOCK_MAGIC2(ieee802_11, equalize_symbols); +GR_SWIG_BLOCK_MAGIC2(ieee802_11, ether_encap); +GR_SWIG_BLOCK_MAGIC2(ieee802_11, frame_equalizer); GR_SWIG_BLOCK_MAGIC2(ieee802_11, mac); GR_SWIG_BLOCK_MAGIC2(ieee802_11, mapper); +GR_SWIG_BLOCK_MAGIC2(ieee802_11, moving_average_cc); +GR_SWIG_BLOCK_MAGIC2(ieee802_11, moving_average_ff); GR_SWIG_BLOCK_MAGIC2(ieee802_11, parse_mac); GR_SWIG_BLOCK_MAGIC2(ieee802_11, sync_long); GR_SWIG_BLOCK_MAGIC2(ieee802_11, sync_short);