This commit is contained in:
Bastian Bloessl
2013-03-24 17:34:51 +01:00
commit 8e266d3f5c
85 changed files with 23053 additions and 0 deletions
+49
View File
@@ -0,0 +1,49 @@
#
# Copyright (C) 2013 Bastian Bloessl <bloessl@ccs-labs.org>
#
# 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 <http://www.gnu.org/licenses/>.
#
########################################################################
# Setup library
########################################################################
include(GrPlatform) #define LIB_SUFFIX
list(APPEND gr_ieee802_11_sources
ofdm_decode_mac.cc
ofdm_decode_signal.cc
ofdm_equalize_symbols.cc
ofdm_parse_mac.cc
ofdm_sync_long.cc
ofdm_sync_short.cc
)
list(APPEND gr_ieee802_11_libs
${Boost_LIBRARIES}
${GRUEL_LIBRARIES}
${GNURADIO_CORE_LIBRARIES}
)
add_library(gnuradio-ieee802_11 SHARED ${gr_ieee802_11_sources})
target_link_libraries(gnuradio-ieee802_11 ${gr_ieee802_11_libs} itpp gnuradio-fft gnuradio-filter)
set_target_properties(gnuradio-ieee802_11 PROPERTIES DEFINE_SYMBOL "gnuradio_ieee802_11_EXPORTS")
########################################################################
# Install built library files
########################################################################
install(TARGETS gnuradio-ieee802_11
LIBRARY DESTINATION lib${LIB_SUFFIX} # .so/.dylib file
ARCHIVE DESTINATION lib${LIB_SUFFIX} # .lib file
RUNTIME DESTINATION bin # .dll file
)
+426
View File
@@ -0,0 +1,426 @@
/*
* Copyright (C) 2013 Bastian Bloessl <bloessl@ccs-labs.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <gnuradio/ieee802_11/ofdm_decode_mac.h>
#include <gnuradio/gr_io_signature.h>
#include <itpp/itcomm.h>
#include <iostream>
#include <iomanip>
using namespace gr::ieee802_11;
using namespace itpp;
enum ENCODING {
BPSK_1_2,
BPSK_3_4,
QPSK_1_2,
QPSK_3_4,
QAM16_1_2,
QAM16_3_4,
QAM64_2_3,
QAM64_3_4,
};
/**
* OFDM parameters
*/
class GR_IEEE802_11_API ofdm_param {
public:
ofdm_param(ENCODING e) {
encoding = e;
switch(e) {
case BPSK_1_2:
n_bpsc = 1;
n_cbps = 48;
n_dbps = 24;
rate_field = 0x0D; // 0b00001101
break;
case BPSK_3_4:
n_bpsc = 1;
n_cbps = 48;
n_dbps = 36;
rate_field = 0x0F; // 0b00001111
break;
case QPSK_1_2:
n_bpsc = 2;
n_cbps = 96;
n_dbps = 48;
rate_field = 0x05; // 0b00000101
break;
case QPSK_3_4:
n_bpsc = 2;
n_cbps = 96;
n_dbps = 72;
rate_field = 0x07; // 0b00000111
break;
case QAM16_1_2:
n_bpsc = 4;
n_cbps = 192;
n_dbps = 96;
rate_field = 0x09; // 0b00001001
break;
case QAM16_3_4:
n_bpsc = 4;
n_cbps = 192;
n_dbps = 144;
rate_field = 0x0B; // 0b00001011
break;
case QAM64_2_3:
n_bpsc = 6;
n_cbps = 288;
n_dbps = 192;
rate_field = 0x01; // 0b00000001
break;
case QAM64_3_4:
n_bpsc = 6;
n_cbps = 288;
n_dbps = 216;
rate_field = 0x03; // 0b00000011
break;
defaut:
assert(false);
break;
}
}
void print_out() {
std::cout << "OFDM Parameters:" << std::endl;
std::cout << "endcoding :" << encoding << std::endl;
std::cout << "rate_field :" << (int)rate_field << std::endl;
std::cout << "n_bpsc :" << n_bpsc << std::endl;
std::cout << "n_cbps :" << n_cbps << std::endl;
std::cout << "n_dbps :" << n_dbps << std::endl;
}
// data rate
ENCODING encoding;
// rate field of the SIGNAL header
char rate_field;
// number of coded bits per sub carrier
int n_bpsc;
// number of coded bits per OFDM symbol
int n_cbps;
// number of data bits per OFDM symbol
int n_dbps;
};
/**
* packet specific parameters
*/
class tx_param {
public:
tx_param(ofdm_param &ofdm, int psdu_length) {
psdu_size = 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;
// number of padding bits (17-13)
n_pad = n_data - (16 + 8 * psdu_size + 6);
n_encoded_bits = n_sym * ofdm.n_cbps;
}
// PSDU size in bytes
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;
void print_out() {
std::cout << "TX 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;
}
};
class ofdm_decode_mac_impl : public ofdm_decode_mac {
#define dout d_debug && std::cout
public:
ofdm_decode_mac_impl(bool debug) : gr_block("ofdm_decode_mac",
gr_make_io_signature(1, 1, 48 * sizeof(gr_complex)),
gr_make_io_signature(0, 0, 0)),
d_debug(debug),
ofdm(BPSK_1_2),
tx(ofdm, 0) {
message_port_register_out(pmt::mp("out"));
}
~ofdm_decode_mac_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];
int i = 0;
std::vector<gr_tag_t> tags;
const uint64_t nread = this->nitems_read(0);
dout << "Decode MAC: input " << ninput_items[0] << std::endl;
while(i < ninput_items[0]) {
get_tags_in_range(tags, 0, nread + i * 48, nread + (i + 1) * 48 - 1,
pmt::pmt_string_to_symbol("ofdm_start"));
if(tags.size()) {
pmt::pmt_t tuple = tags[0].value;
int len_data = pmt::pmt_to_uint64(pmt::pmt_car(tuple));
int encoding = pmt::pmt_to_uint64(pmt::pmt_cdr(tuple));
ofdm = ofdm_param((ENCODING)encoding);
tx = tx_param(ofdm, len_data);
if(tx.n_sym > 100) {
tx.n_sym = 100;
}
copied = 0;
dout << "Decode MAC: frame start -- len " << len_data
<< " symbols " << tx.n_sym << " encoding "
<< encoding << std::endl;
}
if(copied < tx.n_sym) {
std::memcpy(sym + (copied * 48), in, 48 * sizeof(gr_complex));
copied++;
if(copied == tx.n_sym) {
dout << "received complete frame - decoding" << std::endl;
decode();
break;
}
}
in += 48;
i++;
}
consume(0, i);
return 0;
}
void decode() {
if(ofdm.encoding > 3) {
return;
}
demodulate();
deinterleave();
decode_conv();
descramble();
print_output();
// skip service field
pmt::pmt_t blob = pmt::pmt_make_blob(out_bytes + 2, tx.psdu_size);
message_port_pub(pmt::mp("out"), blob);
}
void demodulate() {
gr_complex s;
for(int i = 0; i < tx.n_sym; i++) {
for(int n = 0; n < 48; n++) {
switch(ofdm.encoding) {
case 0: // BPSK
case 1:
bits[i * 48 + n] = -real(sym[i * 48 + n]);
break;
case 2: // QPSK
case 3:
s = sym[i * 48 + n];
bits[(i * 48 + n) * 2] = -real(s);
bits[(i * 48 + n) * 2 + 1] = -imag(s);
break;
case 4:
case 5:
case 6:
case 7:
default:
assert(false);
}
}
}
}
void deinterleave() {
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 < tx.n_sym; i++) {
for(int k = 0; k < n_cbps; k++) {
deinter[i * n_cbps + second[first[k]]] = bits[i * n_cbps + k];
}
}
}
void decode_conv() {
Punctured_Convolutional_Code code;
ivec generator(2);
generator(0)=0133;
generator(1)=0171;
code.set_generator_polynomials(generator, 7);
bmat puncture_matrix;
switch(ofdm.encoding) {
case 0:
case 2:
puncture_matrix = "1 1; 1 1";
break;
case 1:
case 3:
puncture_matrix = "1 1 0; 1 0 1;";
break;
case 4:
case 5:
case 6:
case 7:
break;
default:
assert(false);
}
code.set_puncture_matrix(puncture_matrix);
code.set_truncation_length(30);
dout << "coding rate " << code.get_rate() << std::endl;
dout << tx.n_encoded_bits << std::endl;
vec rx_signal(deinter, tx.n_encoded_bits);
code.reset();
decoded_bits.set_length(tx.n_encoded_bits);
code.decode_tail(rx_signal, decoded_bits);
//dout << "length decoded " << decoded_bits.size() << std::endl;
//std::cout << decoded_bits << std::endl;
//
}
void descramble () {
int index = 0;
for(int i = 0; i < 7; i++) {
if(decoded_bits(i)) {
index |= 1 << (6 - i);
}
}
int state = scrambler_init[index];
int feedback;
for(int i = 0; i < decoded_bits.size(); i++) {
feedback = ((!!(state & 64))) ^ (!!(state & 8));
out_bits[i] = feedback ^ decoded_bits(i);
state = ((state << 1) & 0x7e) | feedback;
}
for(int i = 0; i < decoded_bits.size(); i++) {
int bit = i % 8;
int byte = i / 8;
if(bit == 0) {
out_bytes[byte] = 0;
}
if(out_bits[i]) {
out_bytes[byte] |= (1 << bit);
}
}
}
void print_output() {
dout << std::endl;
for(int i = 0; i < decoded_bits.size() / 8; i++) {
dout << std::setfill('0') << std::setw(2) << std::hex << ((unsigned int)out_bytes[i] & 0xFF) << std::dec << " ";
if(i % 16 == 15) {
dout << std::endl;
}
}
dout << std::endl;
for(int i = 0; i < decoded_bits.size() / 8; i++) {
if((out_bytes[i] > 31) && (out_bytes[i] < 127)) {
dout << ((char) out_bytes[i]);
} else {
dout << ".";
}
}
dout << std::endl;
}
private:
gr_complex sym[1000 * 48 * 100];
double bits[1000 * 48];
double deinter[1000 * 48];
char out_bits[40000];
char out_bytes[40000];
bvec decoded_bits;
bool d_debug;
tx_param tx;
ofdm_param ofdm;
int copied;
static int scrambler_init[128];
};
ofdm_decode_mac::sptr
ofdm_decode_mac::make(bool debug) {
return gnuradio::get_initial_sptr(new ofdm_decode_mac_impl(debug));
}
int ofdm_decode_mac_impl::scrambler_init[128] = {
0, 73, 18, 91, 36, 109, 54, 127, 72, 1, 90, 19, 108, 37, 126, 55, 89, 16, 75, 2, 125, 52, 111, 38, 17, 88, 3, 74, 53, 124, 39, 110, 50, 123, 32, 105, 22, 95, 4, 77, 122, 51, 104, 33, 94, 23, 76, 5, 107, 34, 121, 48, 79, 6, 93, 20, 35, 106, 49, 120, 7, 78, 21, 92, 100, 45, 118, 63, 64, 9, 82, 27, 44, 101, 62, 119, 8, 65, 26, 83, 61, 116, 47, 102, 25, 80, 11, 66, 117, 60, 103, 46, 81, 24, 67, 10, 86, 31, 68, 13, 114, 59, 96, 41, 30, 87, 12, 69, 58, 115, 40, 97, 15, 70, 29, 84, 43, 98, 57, 112, 71, 14, 85, 28, 99, 42, 113, 56};
+224
View File
@@ -0,0 +1,224 @@
/*
* Copyright (C) 2013 Bastian Bloessl <bloessl@ccs-labs.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <gnuradio/ieee802_11/ofdm_decode_signal.h>
#include <gnuradio/gr_io_signature.h>
#include <iostream>
#include <itpp/itcomm.h>
using namespace gr::ieee802_11;
using namespace itpp;
class ofdm_decode_signal_impl : public ofdm_decode_signal {
#define dout d_debug && std::cout
public:
ofdm_decode_signal_impl(bool debug) : gr_block("ofdm_decode_signal",
gr_make_io_signature(1, 1, 48 * sizeof(gr_complex)),
gr_make_io_signature(1, 1, 48 * sizeof(gr_complex))),
d_debug(debug),
d_copy_symbols(0) {
decoded_bits.set_size(24);
set_relative_rate(1);
set_tag_propagation_policy(gr_block::TPP_DONT);
}
~ofdm_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<gr_tag_t> 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 * 48, nread + (i + 1) * 48 - 1,
pmt::pmt_string_to_symbol("ofdm_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 * 48,
pmt::pmt_string_to_symbol("ofdm_start"),
pmt::pmt_cons(pmt::pmt_from_uint64(d_len),
pmt::pmt_from_uint64(d_encoding)),
pmt::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 ^= 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;
}
if(d_copy_symbols > 57) {
d_copy_symbols = 0;
}
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_debug;
double bits[48];
int d_copy_symbols;
bvec decoded_bits;
static int inter[48];
};
ofdm_decode_signal::sptr
ofdm_decode_signal::make(bool debug) {
return gnuradio::get_initial_sptr(new ofdm_decode_signal_impl(debug));
}
int ofdm_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};
+122
View File
@@ -0,0 +1,122 @@
/*
* Copyright (C) 2013 Bastian Bloessl <bloessl@ccs-labs.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <gnuradio/ieee802_11/ofdm_equalize_symbols.h>
#include <gnuradio/gr_io_signature.h>
#include <iostream>
using namespace gr::ieee802_11;
class ofdm_equalize_symbols_impl : public ofdm_equalize_symbols {
#define dout d_debug && std::cout
public:
ofdm_equalize_symbols_impl(bool debug) : gr_block("ofdm_equalize_symbols",
gr_make_io_signature(1, 1, 64 * sizeof(gr_complex)),
gr_make_io_signature(1, 1, 48 * sizeof(gr_complex))),
d_debug(debug) {
set_relative_rate(1);
}
~ofdm_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) {
const gr_complex *in = (const gr_complex*)input_items[0];
gr_complex *out = (gr_complex*)output_items[0];
int noutput = noutput_items;
int i = 0;
std::vector<gr_tag_t> tags;
const uint64_t nread = nitems_read(0);
dout << "SYMBOLS: input " << ninput_items[0] << " output " << noutput_items << std::endl;
while((i < ninput_items[0]) && (i < noutput)) {
get_tags_in_range(tags, 0, nread + i * 64, nread + (i + 1) * 64 - 1,
pmt::pmt_string_to_symbol("ofdm_start"));
if(tags.size()) {
index = 0;
}
gr_complex p = POLARITY[index];
index++;
double p1 = arg( p * in[11]);
double p2 = arg( p * in[25] * conj(p * in[11])) + p1;
double p3 = arg( p * in[39] * conj(p * in[25])) + p2;
double p4 = arg(-p * in[53] * conj(p * in[39])) + p3;
double my = (p1 + p2 + p3 + p4) / 4;
double mx = (11.0 + 25 + 39 + 53) / 4;
double var = (((11.0 * 11.0) + (25.0 * 25.0) + (39.0 * 39.0) + (53.0 * 53.0)) / 4) - (mx * mx);
double cov = (( (p1 * 11) + (p2 * 25) + (p3 * 39) + (p4 * 53) ) / 4) - (mx * my);
double beta = cov / var;
double alpha = my - beta * mx;
int o = 0;
for(int n = 0; n < 64; n++) {
if( (n == 11) || (n == 25) || (n == 32) || (n == 39) || (n == 53) || (n < 6) || ( n > 58)) {
continue;
} else {
out[o] = in[n] * exp(gr_complex(0, -n * beta - alpha));
o++;
}
}
i++;
in += 64;
out += 48;
}
dout << "SYMBOLS: produced / consumed " << i << std::endl;
consume(0, i);
return i;
}
private:
int index;
const bool d_debug;
static const gr_complex POLARITY[127];
};
const gr_complex ofdm_equalize_symbols_impl::POLARITY[127] = {
1, 1, 1, 1,-1,-1,-1, 1,-1,-1,-1,-1, 1, 1,-1, 1,
-1,-1, 1, 1,-1, 1, 1,-1, 1, 1, 1, 1, 1, 1,-1, 1,
1, 1,-1, 1, 1,-1,-1, 1, 1, 1,-1, 1,-1,-1,-1, 1,
-1, 1,-1,-1, 1,-1,-1, 1, 1, 1, 1, 1,-1,-1, 1, 1,
-1,-1, 1,-1, 1,-1, 1, 1,-1,-1,-1, 1, 1,-1,-1,-1,
-1, 1,-1,-1, 1,-1, 1, 1, 1, 1,-1, 1,-1, 1,-1, 1,
-1,-1,-1,-1,-1, 1,-1, 1, 1,-1, 1,-1, 1, 1, 1,-1,
-1, 1,-1,-1,-1, 1, 1, 1,-1,-1,-1,-1,-1,-1,-1 };
ofdm_equalize_symbols::sptr
ofdm_equalize_symbols::make(bool debug) {
return gnuradio::get_initial_sptr(new ofdm_equalize_symbols_impl(debug));
}
+407
View File
@@ -0,0 +1,407 @@
/*
* Copyright (C) 2013 Bastian Bloessl <bloessl@ccs-labs.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <gnuradio/ieee802_11/ofdm_parse_mac.h>
#include "ofdm_parse_mac_impl.h"
#include <gr_io_signature.h>
#include <gr_block_detail.h>
#include <string>
using namespace gr::ieee802_11;
class ofdm_parse_mac_impl : public ofdm_parse_mac {
#define dout d_debug && std::cout
public:
ofdm_parse_mac_impl(bool debug) :
gr_block("ofdm_parse_mac",
gr_make_io_signature (0, 0, 0),
gr_make_io_signature (0, 0, 0)),
d_debug(debug) {
message_port_register_out(pmt::mp("out"));
message_port_register_in(pmt::mp("in"));
set_msg_handler(pmt::mp("in"), boost::bind(&ofdm_parse_mac_impl::parse, this, _1));
}
~ofdm_parse_mac_impl() {
}
unsigned int update_crc32(unsigned int crc, const char *data, size_t len) {
int j;
unsigned int byte, mask;
static unsigned int table[256];
/* Set up the table if necesary */
if (table[1] == 0) {
for (byte = 0; byte <= 255; byte++) {
crc = byte;
for (j = 7; j >= 0; j--) {
mask = -(crc & 1);
crc = (crc >> 1) ^ (0xEDB88320 & mask);
}
table[byte] = crc;
}
}
/* Calculate the CRC32*/
size_t i = 0;
crc = 0xFFFFFFFF;
for (i = 0; i < len; i++) {
byte = data[i]; //Get next byte
crc = (crc >> 8) ^ table[(crc ^ byte) & 0xFF];
}
unsigned int crc_reversed;
crc_reversed = 0x00000000;
for (j = 31; j >= 0; j--) {
crc_reversed |= ((crc >> j) & 1) << (31 - j);
}
return crc;
}
unsigned int crc32(const char *buf, int len) {
return update_crc32(0xffffffff, buf, len) ^ 0xffffffff;
}
void parse(pmt::pmt_t msg) {
if(pmt::pmt_is_eof_object(msg)) {
message_port_pub(pmt::mp("out"), pmt::PMT_EOF);
detail().get()->set_done(true);
return;
}
assert(pmt::pmt_is_blob(msg));
int data_len = pmt::pmt_blob_length(msg);
mac_header *h = (mac_header*)pmt::pmt_blob_data(msg);
dout << std::endl << "new mac frame (length " << data_len << ")" << std::endl;
dout << "=========================================" << std::endl;
if(data_len < 20) {
dout << "frame too short to parse (<20)" << std::endl;
return;
}
#define HEX(a) std::hex << std::setfill('0') << std::setw(2) << int(a) << std::dec
dout << "duration: " << HEX(h->duration >> 8) << " " << HEX(h->duration & 0xff) << std::endl;
dout << "frame control: " << HEX(h->frame_control >> 8) << " " << HEX(h->frame_control & 0xff);
switch((h->frame_control >> 2) & 3) {
case 0:
dout << " (MANAGEMENT)" << std::endl;
parse_management((char*)h, data_len);
break;
case 1:
dout << " (CONTROL)" << std::endl;
parse_control((char*)h, data_len);
break;
case 2:
dout << " (DATA)" << std::endl;
parse_data((char*)h, data_len);
break;
default:
dout << " (unknown)" << std::endl;
break;
}
bool crc = check_crc((char*)pmt::pmt_blob_data(msg), data_len);
dout << "crc ";
dout << (crc ? "correct" : "wrong") << std::endl;
if(!crc || data_len < 32) {
return;
}
char *frame = (char*)pmt::pmt_blob_data(msg);
frame[data_len - 4] = '\n';
// DATA
if((((h->frame_control) >> 2) & 63) == 2) {
print_ascii(frame + 24, data_len - 24 - 4);
pmt::pmt_t payload = pmt::pmt_make_blob(frame + 24, data_len - 24 - 3);
message_port_pub(pmt::mp("out"), pmt::pmt_cons(pmt::PMT_NIL, payload));
// QoS Data
} else if((((h->frame_control) >> 2) & 63) == 34) {
print_ascii(frame + 26, data_len - 26 - 4);
pmt::pmt_t payload = pmt::pmt_make_blob(frame + 26, data_len - 26 - 3);
message_port_pub(pmt::mp("out"), pmt::pmt_cons(pmt::PMT_NIL, payload));
}
}
void parse_management(char *buf, int length) {
mac_header* h = (mac_header*)buf;
if(length < 24) {
dout << "too short for a management frame" << std::endl;
return;
}
dout << "Subtype: ";
switch(((h->frame_control) >> 4) & 0xf) {
case 0:
dout << "Association Request";
break;
case 1:
dout << "Association Response";
break;
case 2:
dout << "Reassociation Request";
break;
case 3:
dout << "Reassociation Response";
break;
case 4:
dout << "Probe Request";
break;
case 5:
dout << "Probe Response";
break;
case 6:
dout << "Timing Advertisement";
break;
case 7:
dout << "Reserved";
break;
case 8:
dout << "Beacon" << std::endl;
if(length < 38) {
return;
}
{
uint8_t* len = (uint8_t*) (buf + 24 + 13);
if(length < 38 + *len) {
return;
}
std::string s(buf + 24 + 14, *len);
dout << "SSID: " << s;
}
break;
case 9:
dout << "ATIM";
break;
case 10:
dout << "Disassociation";
break;
case 11:
dout << "Authentication";
break;
case 12:
dout << "Deauthentication";
break;
case 13:
dout << "Action";
break;
case 14:
dout << "Action No ACK";
break;
case 15:
dout << "Reserved";
break;
default:
break;
}
dout << std::endl;
dout << "seq nr: " << int(h->seq_control >> 4) << std::endl;
dout << "mac 1: ";
print_mac_address(h->addr1, true);
dout << "mac 2: ";
print_mac_address(h->addr2, true);
dout << "mac 3: ";
print_mac_address(h->addr3, true);
}
void parse_data(char *buf, int length) {
mac_header* h = (mac_header*)buf;
if(length < 24) {
dout << "too short for a data frame" << std::endl;
return;
}
dout << "Subtype: ";
switch(((h->frame_control) >> 4) & 0xf) {
case 0:
dout << "Data";
break;
case 1:
dout << "Data + CF-ACK";
break;
case 2:
dout << "Data + CR-Poll";
break;
case 3:
dout << "Data + CF-ACK + CF-Poll";
break;
case 4:
dout << "Null";
break;
case 5:
dout << "CF-ACK";
break;
case 6:
dout << "CF-Poll";
break;
case 7:
dout << "CF-ACK + CF-Poll";
break;
case 8:
dout << "QoS Data";
break;
case 9:
dout << "QoS Data + CF-ACK";
break;
case 10:
dout << "QoS Data + CF-Poll";
break;
case 11:
dout << "QoS Data + CF-ACK + CF-Poll";
break;
case 12:
dout << "QoS Null";
break;
case 13:
dout << "Reserved";
break;
case 14:
dout << "QoS CF-Poll";
break;
case 15:
dout << "QoS CF-ACK + CF-Poll";
break;
default:
break;
}
dout << std::endl;
dout << "seq nr: " << int(h->seq_control >> 4) << std::endl;
dout << "mac 1: ";
print_mac_address(h->addr1, true);
dout << "mac 2: ";
print_mac_address(h->addr2, true);
dout << "mac 3: ";
print_mac_address(h->addr3, true);
}
void parse_control(char *buf, int length) {
mac_header* h = (mac_header*)buf;
dout << "Subtype: ";
switch(((h->frame_control) >> 4) & 0xf) {
case 7:
dout << "Control Wrapper";
break;
case 8:
dout << "Block ACK Requrest";
break;
case 9:
dout << "Block ACK";
break;
case 10:
dout << "PS Poll";
break;
case 11:
dout << "RTS";
break;
case 12:
dout << "CTS";
break;
case 13:
dout << "ACK";
break;
case 14:
dout << "CF-End";
break;
case 15:
dout << "CF-End + CF-ACK";
break;
default:
dout << "Reserved";
break;
}
dout << std::endl;
dout << "RA: ";
print_mac_address(h->addr1, true);
dout << "TA: ";
print_mac_address(h->addr2, true);
}
void print_mac_address(uint8_t *addr, bool new_line = false) {
if(!d_debug) {
return;
}
std::cout << std::setfill('0') << std::hex << std::setw(2);
for(int i = 0; i < 6; i++) {
std::cout << (int)addr[i];
if(i != 5) {
std::cout << ":";
}
}
std::cout << std::dec;
if(new_line) {
std::cout << std::endl;
}
}
void print_ascii(char* buf, int length) {
for(int i = 0; i < length; i++) {
if((buf[i] > 31) && (buf[i] < 127)) {
dout << buf[i];
} else {
dout << ".";
}
}
dout << std::endl;
}
bool check_crc(char *data, int len) {
unsigned int crc = crc32(data, len);
if(crc == 558161692) {
return true;
}
return false;
}
private:
bool d_debug;
};
ofdm_parse_mac::sptr
ofdm_parse_mac::make(bool debug) {
return gnuradio::get_initial_sptr(new ofdm_parse_mac_impl(debug));
}
+30
View File
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2013 Bastian Bloessl <bloessl@ccs-labs.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef INCLUDED_GR_IEEE802_11_OFDM_PARSE_MAC_IMPL_H
#define INCLUDED_GR_IEEE802_11_OFDM_PARSE_MAC_IMPL_H
struct mac_header {
uint16_t frame_control;
uint16_t duration;
uint8_t addr1[6];
uint8_t addr2[6];
uint8_t addr3[6];
uint16_t seq_control;
}__attribute__((packed));
#endif /* INCLUDED_GR_IEEE802_11_OFDM_PARSE_MAC_IMPL_H */
+262
View File
@@ -0,0 +1,262 @@
/*
* Copyright (C) 2013 Bastian Bloessl <bloessl@ccs-labs.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <gnuradio/ieee802_11/ofdm_sync_long.h>
#include <gnuradio/gr_io_signature.h>
#include <filter/fir_filter.h>
#include <fft/fft.h>
#include <list>
#include <tuple>
#include <iostream>
using namespace gr::ieee802_11;
class ofdm_sync_long_impl : public ofdm_sync_long {
#define dout d_debug && std::cout
public:
ofdm_sync_long_impl(unsigned int sync_lenght, unsigned int freq_est, bool debug) : gr_block("ofdm_sync_long",
gr_make_io_signature2(2, 2, sizeof(gr_complex), sizeof(gr_complex)),
gr_make_io_signature(1, 1, sizeof(gr_complex))),
d_debug(debug),
d_offset(0),
d_freq_est(0),
d_state(SYNC),
SYNC_LENGTH(sync_lenght),
FREQ_EST(freq_est) {
set_tag_propagation_policy(gr_block::TPP_DONT);
d_fir = new gr::filter::kernel::fir_filter_ccc(1, LONG);
d_correlation = gr::fft::malloc_complex(8192);
}
~ofdm_sync_long_impl(){
delete d_fir;
gr::fft::free(d_correlation);
}
int general_work (int noutput, 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];
const gr_complex *in_delayed = (const gr_complex*)input_items[1];
gr_complex *out = (gr_complex*)output_items[0];
dout << "LONG ninput[0] " << ninput_items[0] << " ninput[1] " <<
ninput_items[1] << " noutput " << noutput <<
" state " << d_state << std::endl;
int ninput = std::min(ninput_items[0], ninput_items[1]);
const unsigned int nread = nitems_read(0);
get_tags_in_range(d_tags, 0, nread, nread + ninput);
if (d_tags.size()) {
std::sort(d_tags.begin(), d_tags.end(), gr_tag_t::offset_compare);
const gr_tag_t &tag = d_tags.front();
const uint64_t offset = tag.offset;
if(offset > nread) {
ninput = offset - nread;
} else {
if(d_state == COPY) {
d_state = RESET;
}
}
}
int i = 0;
int o = 0;
switch(d_state) {
case SYNC:
d_fir->filterN(d_correlation, in, std::min(SYNC_LENGTH, std::max(ninput - 63, 0)));
while(i + 63 < ninput) {
if(d_offset < FREQ_EST) {
d_freq_est += in[i] * conj(in[i + 16]);
}
d_cor.push_back(std::tuple<double, int>(abs(d_correlation[i]), d_offset));
i++;
d_offset++;
if(d_offset == SYNC_LENGTH) {
search_frame_start();
d_offset = 0;
d_state = COPY;
break;
}
}
break;
case COPY:
while(i < ninput) {
int rel = d_offset - d_frame_start;
if( (rel >= 0) && (rel % 80 > 15)) {
if(o >= noutput) {
break;
}
if(rel == 16) {
assert(o == 0);
add_item_tag(0, nitems_written(0) + o,
pmt::pmt_string_to_symbol("ofdm_start"),
pmt::PMT_T,
pmt::pmt_string_to_symbol(name()));
}
out[o] = in_delayed[i] * exp(gr_complex(0, d_offset * arg(d_freq_est) / 16));
o++;
}
i++;
d_offset++;
}
break;
case RESET:
while(o < noutput) {
int rel = (d_offset - d_frame_start) % 80;
if(!rel) {
d_offset = 0;
d_freq_est = gr_complex(0, 0);
d_state = SYNC;
break;
}
d_offset++;
out[o] = 0;
o++;
}
break;
default:
assert(false);
break;
}
dout << "produced : " << o << " consumed: " << i << std::endl;
consume(0, i);
consume(1, i);
return o;
}
void forecast (int noutput_items, gr_vector_int &ninput_items_required) {
if(d_state == SYNC) {
ninput_items_required[0] = 64;
ninput_items_required[1] = 64;
} else {
ninput_items_required[0] = noutput_items;
ninput_items_required[1] = noutput_items;
}
0 && dout << "LONG forecast noutput_items: " << noutput_items
<< " state: " << d_state
<< " req[0] " << ninput_items_required[0]
<< " req[1] " << ninput_items_required[1]
<< std::endl;
}
void search_frame_start() {
assert(d_cor.size() == SYNC_LENGTH);
d_cor.sort();
d_cor.reverse();
std::list<std::tuple<double, int>>::iterator it = d_cor.begin();
int m1 = std::get<1>(*it);
it++;
int m2 = std::get<1>(*it);
it++;
int m3 = std::get<1>(*it);
int m = std::max(m1, std::max(m2, m3));
d_frame_start = m + 64;
dout << "d_frame_start " << d_frame_start << std::endl;
dout << "peaks " << m1 << " " << m2 << " " << m3 << std::endl;
//for(it = d_cor.begin(); it != d_cor.end(); it++) {
//std::cout << std::get<0>(*it) << " " << std::get<1>(*it) << std::endl;
//}
d_cor.clear();
}
private:
enum {SYNC, COPY, RESET} d_state;
int d_offset;
int d_frame_start;
gr_complex d_freq_est;
gr_complex *d_correlation;
std::list<std::tuple<double, int>> d_cor;
std::vector<gr_tag_t> d_tags;
gr::filter::kernel::fir_filter_ccc *d_fir;
const bool d_debug;
const int SYNC_LENGTH;
const int FREQ_EST;
static const std::vector<gr_complex> LONG;
};
ofdm_sync_long::sptr
ofdm_sync_long::make(unsigned int sync_length, unsigned int freq_est, bool debug) {
return gnuradio::get_initial_sptr(new ofdm_sync_long_impl(sync_length, freq_est, debug));
}
const std::vector<gr_complex> ofdm_sync_long_impl::LONG = {
gr_complex( -0.04097-0.9626011), gr_complex( 0.3179976-0.8892635), gr_complex( 0.7746551+0.6623833),
gr_complex( 0.1688942+0.2230874), gr_complex( 0.4785908-0.7016541), gr_complex( -0.9210497-0.441444),
gr_complex( -0.3065277-0.8493673), gr_complex( 0.7803301-0.2071068), gr_complex( 0.4267019+0.0326106),
gr_complex( 0.0079118-0.9200371), gr_complex( -1.094439-0.379038), gr_complex( 0.1958068-0.4682544),
gr_complex( 0.4693501-0.119512), gr_complex( -0.179866+1.285259), gr_complex( 0.9539127-0.0327648),
gr_complex( 0.5-0.5), gr_complex( 0.2953435+0.7867532), gr_complex( -0.4576508+0.3143887),
gr_complex( -1.050101+0.521818), gr_complex( 0.6577466+0.7388524), gr_complex( 0.5564548+0.1129757),
gr_complex( -0.4824808+0.650289), gr_complex( -0.451641-0.1744314), gr_complex( -0.28033-1.207107),
gr_complex( -0.9750961-0.1325297), gr_complex( -1.018595-0.164011), gr_complex( 0.6005896-0.5923234),
gr_complex( -0.0224476+0.4301941), gr_complex( -0.7351004+0.9210297), gr_complex( 0.7337324+0.8469733),
gr_complex( 0.0982767+0.7807964), gr_complex( -1.25+0), gr_complex( 0.0982767-0.7807964),
gr_complex( 0.7337324-0.8469733), gr_complex( -0.7351004-0.9210297), gr_complex( -0.0224476-0.4301941),
gr_complex( 0.6005896+0.5923234), gr_complex( -1.018595+0.164011), gr_complex( -0.9750961+0.1325297),
gr_complex( -0.28033+1.207107), gr_complex( -0.451641+0.1744314), gr_complex( -0.4824808-0.650289),
gr_complex( 0.5564548-0.1129757), gr_complex( 0.6577466-0.7388524), gr_complex( -1.050101-0.521818),
gr_complex( -0.4576508-0.3143887), gr_complex( 0.2953435-0.7867532), gr_complex( 0.5+0.5),
gr_complex( 0.9539127+0.0327648), gr_complex( -0.179866-1.285259), gr_complex( 0.4693501+0.119512),
gr_complex( 0.1958068+0.4682544), gr_complex( -1.094439+0.379038), gr_complex( 0.0079118+0.9200371),
gr_complex( 0.4267019-0.0326106), gr_complex( 0.7803301+0.2071068), gr_complex( -0.3065277+0.8493673),
gr_complex( -0.9210497+0.441444), gr_complex( 0.4785908+0.7016541), gr_complex( 0.1688942-0.2230874),
gr_complex( 0.7746551-0.6623833), gr_complex( 0.3179976+0.8892635), gr_complex( -0.04097+0.9626011),
gr_complex( 1.25+0)};
+134
View File
@@ -0,0 +1,134 @@
/*
* Copyright (C) 2013 Bastian Bloessl <bloessl@ccs-labs.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <gnuradio/ieee802_11/ofdm_sync_short.h>
#include <gnuradio/gr_io_signature.h>
#include <iostream>
using namespace gr::ieee802_11;
class ofdm_sync_short_impl : public ofdm_sync_short {
#define dout d_debug && std::cout
public:
ofdm_sync_short_impl(double threshold, unsigned int max_samples,
unsigned int min_plateau, bool debug) : gr_block("ofdm_sync_short",
gr_make_io_signature2(2, 2, sizeof(gr_complex), sizeof(float)),
gr_make_io_signature(1, 1, sizeof(gr_complex))),
d_debug(debug),
d_state(SEARCH),
d_plateau(0),
MAX_SAMPLES(max_samples),
MIN_PLATEAU(min_plateau),
d_threshold(threshold) {
set_tag_propagation_policy(gr_block::TPP_DONT);
}
~ofdm_sync_short_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];
const float *in2 = (const float*)input_items[1];
gr_complex *out = (gr_complex*)output_items[0];
int noutput = noutput_items;
int ninput = std::min(ninput_items[0], ninput_items[1]);
// dout << "SHORT noutput : " << noutput << " ninput: " << ninput_items[0] << std::endl;
switch(d_state) {
case SEARCH: {
int i;
for(i = 0; i < ninput; i++) {
if(in2[i] > d_threshold) {
if(d_plateau < MIN_PLATEAU) {
d_plateau++;
} else {
d_state = COPY;
d_copy_left = MAX_SAMPLES;
d_plateau = 0;
insert_tag(nitems_written(0));
dout << "SHORT Frame!" << std::endl;
break;
}
} else {
d_plateau = 0;
}
}
consume(0, i);
consume(1, i);
return 0;
}
case COPY: {
int to_copy = std::min(d_copy_left, std::min(noutput, ninput));
std::memcpy(out, in, to_copy * sizeof(gr_complex));
d_copy_left -= to_copy;
if(!d_copy_left) {
d_state = SEARCH;
}
dout << "SHORT copied " << to_copy << std::endl;
consume(0, to_copy);
consume(1, to_copy);
return to_copy;
}
}
throw std::runtime_error("sync short: unknown state");
return 0;
}
void insert_tag(uint64_t item) {
dout << "SYNC SHORT: insert ofdm_start at: " << item << std::endl;
const pmt::pmt_t key = pmt::pmt_string_to_symbol("ofdm_start");
const pmt::pmt_t value = pmt::PMT_T;
const pmt::pmt_t srcid = pmt::pmt_string_to_symbol(name());
add_item_tag(0, item, key, value, srcid);
}
private:
enum {SEARCH, COPY} d_state;
int d_copy_left;
int d_plateau;
const double d_threshold;
const bool d_debug;
const unsigned int MAX_SAMPLES;
const unsigned int MIN_PLATEAU;
};
ofdm_sync_short::sptr
ofdm_sync_short::make(double threshold, unsigned int max_samples,
unsigned int min_plateau, bool debug) {
return gnuradio::get_initial_sptr(new ofdm_sync_short_impl(threshold,
max_samples, min_plateau, debug));
}