init
This commit is contained in:
@@ -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
|
||||
)
|
||||
@@ -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};
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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)};
|
||||
@@ -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));
|
||||
}
|
||||
Reference in New Issue
Block a user