/* * Copyright (C) 2013 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 #include #include #include using namespace gr::ieee802_11; using namespace itpp; class ofdm_decode_mac_impl : public ofdm_decode_mac { public: ofdm_decode_mac_impl(bool log, bool debug) : block("ofdm_decode_mac", gr::io_signature::make(1, 1, 48 * sizeof(gr_complex)), gr::io_signature::make(0, 0, 0)), d_log(log), d_debug(debug), d_ofdm(BPSK_1_2), d_tx(d_ofdm, 0), d_frame_complete(true) { message_port_register_out(pmt::mp("out")); // bpsk int bpsk_bits[] = {0, 1}; bpsk.set(cvec(BPSK_D, 2), ivec(bpsk_bits, 2)); // qpsk int qpsk_bits[] = {0, 1, 2, 3}; qpsk.set(cvec(QPSK_D, 4), ivec(qpsk_bits, 4)); // qam16 int qam16_bits[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; qam16.set(cvec(QAM16_D, 16), ivec(qam16_bits, 16)); // qam64 int qam64_bits[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}; qam64.set(cvec(QAM64_D, 64), ivec(qam64_bits, 64)); } 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 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, nread + i + 1, pmt::string_to_symbol("ofdm_start")); if(tags.size()) { if (d_frame_complete == false) { dout << "Warning: starting to receive new frame before old frame was complete" << std::endl; dout << "Already copied " << copied << " out of " << d_tx.n_sym << " symbols of last frame" << std::endl; } d_frame_complete = false; pmt::pmt_t tuple = tags[0].value; int len_data = pmt::to_uint64(pmt::car(tuple)); int encoding = pmt::to_uint64(pmt::cdr(tuple)); ofdm_param ofdm = ofdm_param((Encoding)encoding); tx_param tx = tx_param(ofdm, len_data); // sanity check, more than MAX_SYM may indicate garbage if(tx.n_sym <= MAX_SYM && tx.n_encoded_bits <= MAX_BITS) { d_ofdm = ofdm; d_tx = tx; copied = 0; dout << "Decode MAC: frame start -- len " << len_data << " symbols " << tx.n_sym << " encoding " << encoding << std::endl; } else { dout << "Dropping frame which is too large (symbols or bits)" << std::endl; } } if(copied < d_tx.n_sym) { dout << "copy one symbol, copied " << copied << " out of " << d_tx.n_sym << std::endl; std::memcpy(sym + (copied * 48), in, 48 * sizeof(gr_complex)); copied++; if(copied == d_tx.n_sym) { dout << "received complete frame - decoding" << std::endl; decode(); in += 48; i++; d_frame_complete = true; break; } } in += 48; i++; } consume(0, i); return 0; } void decode() { demodulate(); deinterleave(); decode_conv(); descramble(); print_output(); // skip service field boost::crc_32_type result; result.process_bytes(out_bytes + 2, d_tx.psdu_size); if(result.checksum() != 558161692) { dout << "checksum wrong -- dropping" << std::endl; return; } mylog(boost::format("encoding: %1% - length: %2% - symbols: %3%") % d_ofdm.encoding % d_tx.psdu_size % d_tx.n_sym); // create PDU pmt::pmt_t blob = pmt::make_blob(out_bytes + 2, d_tx.psdu_size - 4); pmt::pmt_t enc = pmt::from_uint64(d_ofdm.encoding); pmt::pmt_t dict = pmt::make_dict(); dict = pmt::dict_add(dict, pmt::mp("encoding"), enc); message_port_pub(pmt::mp("out"), pmt::cons(dict, blob)); } void demodulate() { cvec symbols; symbols.set_length(d_tx.n_sym * 48); for(int i = 0; i < d_tx.n_sym * 48; i++) { symbols[i] = std::complex(sym[i]); } switch(d_ofdm.encoding) { case BPSK_1_2: case BPSK_3_4: bits = to_vec(bpsk.demodulate_bits(symbols)); break; case QPSK_1_2: case QPSK_3_4: bits = to_vec(qpsk.demodulate_bits(symbols)); break; case QAM16_1_2: case QAM16_3_4: bits = to_vec(qam16.demodulate_bits(symbols)); break; case QAM64_2_3: case QAM64_3_4: bits = to_vec(qam64.demodulate_bits(symbols)); break; } // I hate the guy who wrote itpp bits = bits * (-2) + 1; } void deinterleave() { int n_cbps = d_ofdm.n_cbps; int first[n_cbps]; int second[n_cbps]; int s = std::max(d_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 < d_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(d_ofdm.encoding) { case BPSK_1_2: case QPSK_1_2: case QAM16_1_2: puncture_matrix = "1 1; 1 1"; break; case BPSK_3_4: case QPSK_3_4: case QAM16_3_4: case QAM64_3_4: puncture_matrix = "1 1 0; 1 0 1;"; break; case QAM64_2_3: puncture_matrix = "1 1 1 1 1 1; 1 0 1 0 1 0;"; break; } code.set_puncture_matrix(puncture_matrix); code.set_truncation_length(30); dout << "coding rate " << code.get_rate() << std::endl; dout << d_tx.n_encoded_bits << std::endl; vec rx_signal(deinter, d_tx.n_encoded_bits); code.reset(); decoded_bits.set_length(d_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 state = 0; for(int i = 0; i < 7; i++) { if(decoded_bits(i)) { state |= 1 << (6 - i); } } int feedback; for(int i = 7; i < decoded_bits.size(); i++) { feedback = ((!!(state & 64))) ^ (!!(state & 8)); out_bits[i] = feedback ^ (int)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]; vec bits; double deinter[1000 * 48]; char out_bits[40000]; char out_bytes[40000]; bvec decoded_bits; bool d_debug; bool d_log; tx_param d_tx; ofdm_param d_ofdm; int copied; bool d_frame_complete; Modulator > bpsk; Modulator > qpsk; Modulator > qam16; Modulator > qam64; }; ofdm_decode_mac::sptr ofdm_decode_mac::make(bool log, bool debug) { return gnuradio::get_initial_sptr(new ofdm_decode_mac_impl(log, debug)); }