diff --git a/include/ieee802-11/CMakeLists.txt b/include/ieee802-11/CMakeLists.txt index 6ba25c9..d47195f 100644 --- a/include/ieee802-11/CMakeLists.txt +++ b/include/ieee802-11/CMakeLists.txt @@ -14,20 +14,75 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # +include(GrPython) + +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py " +#!${PYTHON_EXECUTABLE} + +import sys, os, re +sys.path.append('${GR_RUNTIME_PYTHONPATH}') +os.environ['srcdir'] = '${CMAKE_CURRENT_SOURCE_DIR}' +os.chdir('${CMAKE_CURRENT_BINARY_DIR}') + +if __name__ == '__main__': + sys.path.append('${CMAKE_CURRENT_SOURCE_DIR}/../../python') + import build_utils + root, inp = sys.argv[1:3] + for sig in sys.argv[3:]: + name = re.sub ('X+', sig, root) + d = build_utils.standard_dict(name, sig, 'ieee802_11') + build_utils.expand_template(d, inp) + +") + +macro(expand_h root) + #make a list of all the generated files + unset(expanded_files_h) + foreach(sig ${ARGN}) + string(REGEX REPLACE "X+" ${sig} name ${root}) + list(APPEND expanded_files_h ${CMAKE_CURRENT_BINARY_DIR}/${name}.h) + endforeach(sig) + + #create a command to generate the files + add_custom_command( + OUTPUT ${expanded_files_h} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${root}.h.t + COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B} + ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py + ${root} ${root}.h.t ${ARGN} + ) + + #install rules for the generated h files + list(APPEND generated_includes ${expanded_files_h}) +endmacro(expand_h) + +expand_h(moving_average_XX ff cc) + +add_custom_target(ieee802_11_generated_includes DEPENDS + ${generated_includes} +) ######################################################################## # Install public header files ######################################################################## list(APPEND include_sources + ${generated_includes} api.h ether_encap.h ofdm_decode_mac.h ofdm_decode_signal.h ofdm_equalize_symbols.h + ofdm_freq_est.h + ofdm_mac.h + ofdm_mapper.h ofdm_parse_mac.h + ofdm_pilot.h + ofdm_preamble.h ofdm_sync_long.h ofdm_sync_short.h + wave_llc.h + wave_short_message.h ) install( diff --git a/include/ieee802-11/moving_average_XX.h.t b/include/ieee802-11/moving_average_XX.h.t new file mode 100644 index 0000000..9b9023e --- /dev/null +++ b/include/ieee802-11/moving_average_XX.h.t @@ -0,0 +1,40 @@ +/* + * 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 . + */ +#ifndef @GUARD_NAME@ +#define @GUARD_NAME@ + +#include +#include + +namespace gr { +namespace ieee802_11 { + +class IEEE802_11_API @NAME@ : virtual public sync_block +{ +public: + typedef boost::shared_ptr<@NAME@> sptr; + static sptr make(int length); + + virtual int length() const = 0; + virtual void set_length(int length) = 0; + +}; + +} /* namespace blocks */ +} /* namespace gr */ + +#endif /* @GUARD_NAME@ */ diff --git a/include/ieee802-11/ofdm_decode_mac.h b/include/ieee802-11/ofdm_decode_mac.h index f2c41c7..8cb193c 100644 --- a/include/ieee802-11/ofdm_decode_mac.h +++ b/include/ieee802-11/ofdm_decode_mac.h @@ -28,7 +28,7 @@ class IEEE802_11_API ofdm_decode_mac : virtual public block public: typedef boost::shared_ptr sptr; - static sptr make(bool debug = false); + static sptr make(bool log = false, bool debug = false); }; diff --git a/include/ieee802-11/ofdm_decode_signal.h b/include/ieee802-11/ofdm_decode_signal.h index ff7f196..d334e36 100644 --- a/include/ieee802-11/ofdm_decode_signal.h +++ b/include/ieee802-11/ofdm_decode_signal.h @@ -28,7 +28,7 @@ class IEEE802_11_API ofdm_decode_signal : virtual public block public: typedef boost::shared_ptr sptr; - static sptr make(bool debug = false); + static sptr make(bool log = false, bool debug = false); }; diff --git a/include/ieee802-11/ofdm_freq_est.h b/include/ieee802-11/ofdm_freq_est.h new file mode 100644 index 0000000..b891a81 --- /dev/null +++ b/include/ieee802-11/ofdm_freq_est.h @@ -0,0 +1,38 @@ +/* + * 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 . + */ +#ifndef INCLUDED_IEEE802_11_OFDM_FREQ_EST_H +#define INCLUDED_IEEE802_11_OFDM_FREQ_EST_H + +#include +#include + +namespace gr { +namespace ieee802_11 { + +class IEEE802_11_API ofdm_freq_est : virtual public block +{ +public: + + typedef boost::shared_ptr sptr; + static sptr make(bool log = false, bool debug = false); + +}; + +} // namespace ieee802_11 +} // namespace gr + +#endif /* INCLUDED_IEEE802_11_OFDM_FREQ_EST_H */ diff --git a/include/ieee802-11/ofdm_mac.h b/include/ieee802-11/ofdm_mac.h new file mode 100644 index 0000000..7e8eb6b --- /dev/null +++ b/include/ieee802-11/ofdm_mac.h @@ -0,0 +1,37 @@ +/* + * 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 . + */ +#ifndef INCLUDED_IEEE802_11_OFDM_MAC_H +#define INCLUDED_IEEE802_11_OFDM_MAC_H + +#include +#include + +namespace gr { +namespace ieee802_11 { + +class IEEE802_11_API ofdm_mac : virtual public block +{ +public: + + typedef boost::shared_ptr sptr; + static sptr make(); +}; + +} // namespace ieee802_11 +} // namespace gr + +#endif /* INCLUDED_IEEE802_11_OFDM_MAC_H */ diff --git a/include/ieee802-11/ofdm_mapper.h b/include/ieee802-11/ofdm_mapper.h new file mode 100644 index 0000000..d554113 --- /dev/null +++ b/include/ieee802-11/ofdm_mapper.h @@ -0,0 +1,49 @@ +/* + * 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 . + */ +#ifndef INCLUDED_IEEE802_11_OFDM_MAPPER_H +#define INCLUDED_IEEE802_11_OFDM_MAPPER_H + +#include +#include + +enum Encoding { + BPSK_1_2 = 0, + BPSK_3_4 = 1, + QPSK_1_2 = 2, + QPSK_3_4 = 3, + QAM16_1_2 = 4, + QAM16_3_4 = 5, + QAM64_2_3 = 6, + QAM64_3_4 = 7, +}; + +namespace gr { +namespace ieee802_11 { + +class IEEE802_11_API ofdm_mapper : virtual public block +{ +public: + + typedef boost::shared_ptr sptr; + static sptr make(Encoding mcs, bool debug = false); + virtual void set_encoding(Encoding mcs) = 0; +}; + +} // namespace ieee802_11 +} // namespace gr + +#endif /* INCLUDED_IEEE802_11_OFDM_MAPPER_H */ diff --git a/include/ieee802-11/ofdm_parse_mac.h b/include/ieee802-11/ofdm_parse_mac.h index c00a4e1..1093208 100644 --- a/include/ieee802-11/ofdm_parse_mac.h +++ b/include/ieee802-11/ofdm_parse_mac.h @@ -28,7 +28,7 @@ class IEEE802_11_API ofdm_parse_mac : virtual public block public: typedef boost::shared_ptr sptr; - static sptr make(bool debug); + static sptr make(bool log = false, bool debug = false); }; diff --git a/include/ieee802-11/ofdm_pilot.h b/include/ieee802-11/ofdm_pilot.h new file mode 100644 index 0000000..fb9f6c7 --- /dev/null +++ b/include/ieee802-11/ofdm_pilot.h @@ -0,0 +1,38 @@ +/* + * 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 . + */ +#ifndef INCLUDED_IEEE802_11_PILOT_H +#define INCLUDED_IEEE802_11_PILOT_H + +#include +#include + +namespace gr { +namespace ieee802_11 { + +class IEEE802_11_API ofdm_pilot : virtual public sync_block +{ +public: + + typedef boost::shared_ptr sptr; + static sptr make(bool debug = false); + +}; + +} // namespace ieee802_11 +} // namespace gr + +#endif /* INCLUDED_IEEE802_11_PILOT_H */ diff --git a/include/ieee802-11/ofdm_preamble.h b/include/ieee802-11/ofdm_preamble.h new file mode 100644 index 0000000..e22fcdd --- /dev/null +++ b/include/ieee802-11/ofdm_preamble.h @@ -0,0 +1,38 @@ +/* + * 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 . + */ +#ifndef INCLUDED_IEEE802_11_OFDM_PREAMBLE_H +#define INCLUDED_IEEE802_11_OFDM_PREAMBLE_H + +#include +#include + +namespace gr { +namespace ieee802_11 { + +class IEEE802_11_API ofdm_preamble : virtual public block +{ +public: + + typedef boost::shared_ptr sptr; + static sptr make(bool debug = false); + +}; + +} // namespace ieee802_11 +} // namespace gr + +#endif /* INCLUDED_IEEE802_11_OFDM_PREAMBLE_H */ diff --git a/include/ieee802-11/ofdm_sync_long.h b/include/ieee802-11/ofdm_sync_long.h index 3700140..734b7cb 100644 --- a/include/ieee802-11/ofdm_sync_long.h +++ b/include/ieee802-11/ofdm_sync_long.h @@ -28,8 +28,8 @@ class IEEE802_11_API ofdm_sync_long : virtual public block public: typedef boost::shared_ptr sptr; - static sptr make(unsigned int sync_length, unsigned int freq_est, - bool debug = false); + static sptr make(unsigned int sync_length, + bool log = false, bool debug = false); }; diff --git a/include/ieee802-11/ofdm_sync_short.h b/include/ieee802-11/ofdm_sync_short.h index fb86688..2bfbca2 100644 --- a/include/ieee802-11/ofdm_sync_short.h +++ b/include/ieee802-11/ofdm_sync_short.h @@ -29,7 +29,7 @@ public: typedef boost::shared_ptr sptr; static sptr make(double threshold, unsigned int max_samples, - unsigned int min_plateau, bool debug = false); + unsigned int min_plateau, bool log = false, bool debug = false); }; diff --git a/include/ieee802-11/wave_llc.h b/include/ieee802-11/wave_llc.h new file mode 100644 index 0000000..4c4906d --- /dev/null +++ b/include/ieee802-11/wave_llc.h @@ -0,0 +1,38 @@ +/* + * 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 . + */ +#ifndef INCLUDED_IEEE802_11_WAVE_LLC_H +#define INCLUDED_IEEE802_11_WAVE_LLC_H + +#include +#include + +namespace gr { +namespace ieee802_11 { + +class IEEE802_11_API wave_llc : virtual public block +{ +public: + + typedef boost::shared_ptr sptr; + static sptr make(); + +}; + +} // namespace ieee802_11 +} // namespace gr + +#endif /* INCLUDED_IEEE802_11_WAVE_LLC_H */ diff --git a/include/ieee802-11/wave_short_message.h b/include/ieee802-11/wave_short_message.h new file mode 100644 index 0000000..abcd440 --- /dev/null +++ b/include/ieee802-11/wave_short_message.h @@ -0,0 +1,39 @@ +/* + * 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 . + */ +#ifndef INCLUDED_IEEE802_11_WAVE_SHORT_MESSAGE_H +#define INCLUDED_IEEE802_11_WAVE_SHORT_MESSAGE_H + +#include +#include + +namespace gr { +namespace ieee802_11 { + +class IEEE802_11_API wave_short_message : virtual public block +{ +public: + + virtual void set_version(int version) = 0; + + typedef boost::shared_ptr sptr; + static sptr make(int version); +}; + +} // namespace ieee802_11 +} // namespace gr + +#endif /* INCLUDED_IEEE802_11_WAVE_SHORT_MESSAGE_H */ diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index b7374eb..24b89f8 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -20,15 +20,102 @@ ######################################################################## include(GrPlatform) #define LIB_SUFFIX +file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py " +#!${PYTHON_EXECUTABLE} + +import sys, os, re +sys.path.append('${GR_RUNTIME_PYTHONPATH}') +os.environ['srcdir'] = '${CMAKE_CURRENT_SOURCE_DIR}' +os.chdir('${CMAKE_CURRENT_BINARY_DIR}') + +if __name__ == '__main__': + sys.path.append('${CMAKE_CURRENT_SOURCE_DIR}/../python') + import build_utils + root, inp = sys.argv[1:3] + for sig in sys.argv[3:]: + name = re.sub ('X+', sig, root) + d = build_utils.standard_dict(name, sig, 'ieee802_11') + build_utils.expand_template(d, inp, '_impl') +") + + +macro(expand_cc_h_impl root) + #make a list of all the generated files + unset(expanded_files_cc_impl) + unset(expanded_files_h_impl) + foreach(sig ${ARGN}) + string(REGEX REPLACE "X+" ${sig} name ${root}) + list(APPEND expanded_files_cc_impl ${CMAKE_CURRENT_BINARY_DIR}/${name}_impl.cc) + list(APPEND expanded_files_h_impl ${CMAKE_CURRENT_BINARY_DIR}/${name}_impl.h) + list(APPEND expanded_files_h ${CMAKE_CURRENT_BINARY_DIR}/../include/${name}.h) + endforeach(sig) + + #create a command to generate the _impl.cc files + add_custom_command( + OUTPUT ${expanded_files_cc_impl} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${root}_impl.cc.t + COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B} + ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py + ${root} ${root}_impl.cc.t ${ARGN} + ) + + #create a command to generate the _impl.h files + add_custom_command( + OUTPUT ${expanded_files_h_impl} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${root}_impl.h.t + COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B} + ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py + ${root} ${root}_impl.h.t ${ARGN} + ) + + #make _impl.cc source files depend on headers to force generation + set_source_files_properties(${expanded_files_cc_impl} + PROPERTIES OBJECT_DEPENDS "${expanded_files_h_impl}" + ) + + #make _impl.h source files depend on headers to force generation + set_source_files_properties(${expanded_files_h_impl} + PROPERTIES OBJECT_DEPENDS "${expanded_files_h}" + ) + + #install rules for the generated cc files + list(APPEND generated_sources ${expanded_files_cc_impl}) +endmacro(expand_cc_h_impl) +######################################################################## +# Invoke macro to generate various sources +######################################################################## +expand_cc_h_impl(moving_average_XX cc ff) + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_BINARY_DIR}/../include + ${GR_BLOCKS_INCLUDE_DIRS} + ${GNURADIO_RUNTIME_INCLUDE_DIRS} + ${VOLK_INCLUDE_DIRS} + ${Boost_INCLUDE_DIRS} +) + +######################################################################## +# Setup library +######################################################################## list(APPEND gr_ieee802_11_sources + ${generated_sources} ether_encap_impl.cc ofdm_decode_mac.cc ofdm_decode_signal.cc ofdm_equalize_symbols.cc + ofdm_freq_est.cc + ofdm_mac.cc + ofdm_mapper.cc ofdm_parse_mac.cc + ofdm_pilot.cc + ofdm_preamble.cc ofdm_sync_long.cc ofdm_sync_short.cc - ofdm_utils.cc + utils.cc + wave_llc_impl.cc + wave_short_message_impl.cc ) list(APPEND gr_ieee802_11_libs @@ -39,6 +126,7 @@ list(APPEND gr_ieee802_11_libs ) add_library(gnuradio-ieee802_11 SHARED ${gr_ieee802_11_sources}) +add_dependencies(gnuradio-ieee802_11 ieee802_11_generated_includes) target_link_libraries(gnuradio-ieee802_11 ${gr_ieee802_11_libs} itpp) set_target_properties(gnuradio-ieee802_11 PROPERTIES DEFINE_SYMBOL "gnuradio_ieee802_11_EXPORTS") diff --git a/lib/ether_encap_impl.cc b/lib/ether_encap_impl.cc index 3673c18..f195542 100644 --- a/lib/ether_encap_impl.cc +++ b/lib/ether_encap_impl.cc @@ -16,6 +16,7 @@ */ #include "ether_encap_impl.h" #include "ofdm_parse_mac_impl.h" +#include "utils.h" #include #include @@ -23,8 +24,6 @@ using namespace gr::ieee802_11; -#define dout d_debug && std::cout - ether_encap_impl::ether_encap_impl(bool debug) : block("ether_encap", gr::io_signature::make(0, 0, 0), @@ -32,20 +31,17 @@ ether_encap_impl::ether_encap_impl(bool debug) : d_debug(debug), d_last_seq(123) { - message_port_register_out(pmt::mp("out")); + message_port_register_out(pmt::mp("to tap")); + message_port_register_out(pmt::mp("to wifi")); - message_port_register_in(pmt::mp("in")); - set_msg_handler(pmt::mp("in"), boost::bind(ðer_encap_impl::parse, this, _1)); + message_port_register_in(pmt::mp("from tap")); + set_msg_handler(pmt::mp("from tap"), boost::bind(ðer_encap_impl::from_tap, this, _1)); + message_port_register_in(pmt::mp("from wifi")); + set_msg_handler(pmt::mp("from wifi"), boost::bind(ðer_encap_impl::from_wifi, this, _1)); } void -ether_encap_impl::parse(pmt::pmt_t msg) { - - if(pmt::is_eof_object(msg)) { - message_port_pub(pmt::mp("out"), pmt::PMT_EOF); - detail().get()->set_done(true); - return; - } +ether_encap_impl::from_wifi(pmt::pmt_t msg) { msg = pmt::cdr(msg); @@ -59,11 +55,14 @@ ether_encap_impl::parse(pmt::pmt_t msg) { d_last_seq = mhdr->seq_control; + if(data_len < 33) { dout << "Ether Encap: frame too short to parse (<33)" << std::endl; return; } + // this is more than neeed + char *buf = static_cast(std::malloc(data_len + sizeof(ethernet_header))); ethernet_header *ehdr = reinterpret_cast(buf); if(((mhdr->frame_control >> 2) & 3) != 2) { @@ -71,8 +70,8 @@ ether_encap_impl::parse(pmt::pmt_t msg) { return; } - memcpy(ehdr->dest, mhdr->addr1, 6); - memcpy(ehdr->src, mhdr->addr2, 6); + std::memcpy(ehdr->dest, mhdr->addr1, 6); + std::memcpy(ehdr->src, mhdr->addr2, 6); ehdr->type = 0x0008; char *frame = (char*)pmt::blob_data(msg); @@ -81,15 +80,52 @@ ether_encap_impl::parse(pmt::pmt_t msg) { if((((mhdr->frame_control) >> 2) & 63) == 2) { memcpy(buf + sizeof(ethernet_header), frame + 32, data_len - 32); pmt::pmt_t payload = pmt::make_blob(buf, data_len - 32 + 14); - message_port_pub(pmt::mp("out"), pmt::cons(pmt::PMT_NIL, payload)); + message_port_pub(pmt::mp("to tap"), pmt::cons(pmt::PMT_NIL, payload)); // QoS Data } else if((((mhdr->frame_control) >> 2) & 63) == 34) { memcpy(buf + sizeof(ethernet_header), frame + 34, data_len - 34); pmt::pmt_t payload = pmt::make_blob(buf, data_len - 34 + 14); - message_port_pub(pmt::mp("out"), pmt::cons(pmt::PMT_NIL, payload)); + message_port_pub(pmt::mp("to tap"), pmt::cons(pmt::PMT_NIL, payload)); } + + free(buf); +} + +void +ether_encap_impl::from_tap(pmt::pmt_t msg) { + size_t len = pmt::blob_length(pmt::cdr(msg)); + const char* data = static_cast(pmt::blob_data(pmt::cdr(msg))); + + const ethernet_header *ehdr = reinterpret_cast(data); + + switch(ehdr->type) { + case 0x0008: { + std::cout << "ether type: IP" << std::endl; + + char *buf = static_cast(malloc(len + 8 - sizeof(ethernet_header))); + buf[0] = 0xaa; + buf[1] = 0xaa; + buf[2] = 0x03; + buf[3] = 0x00; + buf[4] = 0x00; + buf[5] = 0x00; + buf[6] = 0x08; + buf[7] = 0x00; + std::memcpy(buf + 8, data + sizeof(ethernet_header), len - sizeof(ethernet_header)); + pmt::pmt_t blob = pmt::make_blob(buf, len + 8 - sizeof(ethernet_header)); + message_port_pub(pmt::mp("to wifi"), pmt::cons(pmt::PMT_NIL, blob)); + break; + } + case 0x0608: + std::cout << "ether type: ARP " << std::endl; + break; + default: + std::cout << "unknown ether type" << std::endl; + break; + } + } ether_encap::sptr diff --git a/lib/ether_encap_impl.h b/lib/ether_encap_impl.h index df70d1b..036b220 100644 --- a/lib/ether_encap_impl.h +++ b/lib/ether_encap_impl.h @@ -34,10 +34,10 @@ namespace ieee802_11 { ether_encap_impl(bool debug); private: - void parse(pmt::pmt_t msg); + void from_tap(pmt::pmt_t msg); + void from_wifi(pmt::pmt_t msg); bool d_debug; - char buf[3000]; uint16_t d_last_seq; }; diff --git a/lib/moving_average_XX_impl.cc.t b/lib/moving_average_XX_impl.cc.t new file mode 100644 index 0000000..90c1d88 --- /dev/null +++ b/lib/moving_average_XX_impl.cc.t @@ -0,0 +1,74 @@ +/* + * 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 "@NAME_IMPL@.h" +#include + +namespace gr { +namespace ieee802_11 { + +@NAME_IMPL@::@NAME_IMPL@(int length) : + sync_block("@NAME@", + io_signature::make(1, 1, sizeof(@I_TYPE@)), + io_signature::make(1, 1, sizeof(@O_TYPE@))), + d_length(length), + d_new_length(length), + d_updated(false) { + set_history(length); +} + +void +@NAME_IMPL@::set_length(int length) { + d_new_length = length; + d_updated = true; +} + +int +@NAME_IMPL@::work(int noutput_items, gr_vector_const_void_star + &input_items, gr_vector_void_star &output_items) { + + if(d_updated) { + d_length = d_new_length; + set_history(d_length); + d_updated = false; + return 0; // history requirements might have changed + } + + const @I_TYPE@ *in = (const @I_TYPE@ *)input_items[0]; + @O_TYPE@ *out = (@O_TYPE@ *)output_items[0]; + + @I_TYPE@ sum = 0; + for(int i = 0; i < d_length-1; i++) { + sum += in[i]; + } + + for(int i = 0; i < noutput_items; i++) { + sum += in[i + d_length - 1]; + out[i] = sum; + sum -= in[i]; + } + + return noutput_items; +} + +@NAME@::sptr +@NAME@::make(int length) { + return gnuradio::get_initial_sptr(new @NAME_IMPL@(length)); +} + + +} /* namespace blocks */ +} /* namespace gr */ diff --git a/lib/moving_average_XX_impl.h.t b/lib/moving_average_XX_impl.h.t new file mode 100644 index 0000000..e6e65f6 --- /dev/null +++ b/lib/moving_average_XX_impl.h.t @@ -0,0 +1,47 @@ +/* + * 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 . + */ +#ifndef @GUARD_NAME_IMPL@ +#define @GUARD_NAME_IMPL@ + +#include + +namespace gr { +namespace ieee802_11 { + +class @NAME_IMPL@ : public @NAME@ +{ +private: + int d_length; + int d_new_length; + bool d_updated; + +public: + @NAME_IMPL@(int length); + + int length() const { return d_new_length; } + void set_length(int length); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + +}; + +} /* namespace blocks */ +} /* namespace gr */ + +#endif /* @GUARD_NAME_IMPL@ */ diff --git a/lib/ofdm_decode_mac.cc b/lib/ofdm_decode_mac.cc index bef097b..427f6da 100644 --- a/lib/ofdm_decode_mac.cc +++ b/lib/ofdm_decode_mac.cc @@ -16,12 +16,11 @@ */ #include -#include "ofdm_utils.h" +#include "utils.h" #include #include #include -#include #include using namespace gr::ieee802_11; @@ -29,17 +28,86 @@ using namespace itpp; class ofdm_decode_mac_impl : public ofdm_decode_mac { -#define dout d_debug && std::cout - public: -ofdm_decode_mac_impl(bool debug) : block("ofdm_decode_mac", +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), ofdm(BPSK_1_2), tx(ofdm, 0) { message_port_register_out(pmt::mp("out")); + + // bpsk + std::complex bpsk_syms[] = {std::complex(-1, 0), std::complex(1, 0)}; + int bpsk_bits[] = {0, 1}; + bpsk.set(cvec(bpsk_syms, 2), ivec(bpsk_bits, 2)); + + // qpsk + std::complex qpsk_syms[] = { + std::complex(-1, -1), std::complex(-1, 1), + std::complex( 1, -1), std::complex( 1, 1)}; + int qpsk_bits[] = {0, 1, 2, 3}; + qpsk.set(cvec(qpsk_syms, 4), ivec(qpsk_bits, 4)); + + // qam16 + std::complex qam16_syms[] = { + std::complex(-0.9487, -0.9487), std::complex(-0.9487, -0.3162), + std::complex(-0.9487, 0.9487), std::complex(-0.9487, 0.3162), + std::complex(-0.3162, -0.9487), std::complex(-0.3162, -0.3162), + std::complex(-0.3162, 0.9487), std::complex(-0.3162, 0.3162), + std::complex(0.9487, -0.9487), std::complex(0.9487, -0.3162), + std::complex(0.9487, 0.9487), std::complex(0.9487, 0.3162), + std::complex(0.3162, -0.9487), std::complex(0.3162, -0.3162), + std::complex(0.3162, 0.9487), std::complex(0.3162, 0.3162)}; + int qam16_bits[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + qam16.set(cvec(qam16_syms, 16), ivec(qam16_bits, 16)); + + // qam64 + std::complex qam64_syms[] = { + std::complex(-1.0801, -1.0801), std::complex(-1.0801, -0.7715), + std::complex(-1.0801, -0.1543), std::complex(-1.0801, -0.4629), + std::complex(-1.0801, 1.0801), std::complex(-1.0801, 0.7715), + std::complex(-1.0801, 0.1543), std::complex(-1.0801, 0.4629), + std::complex(-0.7715, -1.0801), std::complex(-0.7715, -0.7715), + std::complex(-0.7715, -0.1543), std::complex(-0.7715, -0.4629), + std::complex(-0.7715, 1.0801), std::complex(-0.7715, 0.7715), + std::complex(-0.7715, 0.1543), std::complex(-0.7715, 0.4629), + std::complex(-0.1543, -1.0801), std::complex(-0.1543, -0.7715), + std::complex(-0.1543, -0.1543), std::complex(-0.1543, -0.4629), + std::complex(-0.1543, 1.0801), std::complex(-0.1543, 0.7715), + std::complex(-0.1543, 0.1543), std::complex(-0.1543, 0.4629), + std::complex(-0.4629, -1.0801), std::complex(-0.4629, -0.7715), + std::complex(-0.4629, -0.1543), std::complex(-0.4629, -0.4629), + std::complex(-0.4629, 1.0801), std::complex(-0.4629, 0.7715), + std::complex(-0.4629, 0.1543), std::complex(-0.4629, 0.4629), + std::complex(1.0801, -1.0801), std::complex(1.0801, -0.7715), + std::complex(1.0801, -0.1543), std::complex(1.0801, -0.4629), + std::complex(1.0801, 1.0801), std::complex(1.0801, 0.7715), + std::complex(1.0801, 0.1543), std::complex(1.0801, 0.4629), + std::complex(0.7715, -1.0801), std::complex(0.7715, -0.7715), + std::complex(0.7715, -0.1543), std::complex(0.7715, -0.4629), + std::complex(0.7715, 1.0801), std::complex(0.7715, 0.7715), + std::complex(0.7715, 0.1543), std::complex(0.7715, 0.4629), + std::complex(0.1543, -1.0801), std::complex(0.1543, -0.7715), + std::complex(0.1543, -0.1543), std::complex(0.1543, -0.4629), + std::complex(0.1543, 1.0801), std::complex(0.1543, 0.7715), + std::complex(0.1543, 0.1543), std::complex(0.1543, 0.4629), + std::complex(0.4629, -1.0801), std::complex(0.4629, -0.7715), + std::complex(0.4629, -0.1543), std::complex(0.4629, -0.4629), + std::complex(0.4629, 1.0801), std::complex(0.4629, 0.7715), + std::complex(0.4629, 0.1543), std::complex(0.4629, 0.4629)}; + + 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_syms, 64), ivec(qam64_bits, 64)); } ~ofdm_decode_mac_impl(){ @@ -68,13 +136,16 @@ int general_work (int noutput_items, gr_vector_int& ninput_items, int len_data = pmt::to_uint64(pmt::car(tuple)); int encoding = pmt::to_uint64(pmt::cdr(tuple)); - ofdm = ofdm_param((ENCODING)encoding); + ofdm = ofdm_param((Encoding)encoding); tx = tx_param(ofdm, len_data); - if(tx.n_sym > 100) { - tx.n_sym = 100; - } copied = 0; + + // this frame is garbage + if(tx.n_sym > 100) { + // FIXME: make this nicer, this way garbage frames are skipped + copied = tx.n_sym + 1; + } dout << "Decode MAC: frame start -- len " << len_data << " symbols " << tx.n_sym << " encoding " << encoding << std::endl; @@ -102,9 +173,6 @@ int general_work (int noutput_items, gr_vector_int& ninput_items, } void decode() { - if(ofdm.encoding > 3) { - return; - } demodulate(); deinterleave(); decode_conv(); @@ -119,6 +187,9 @@ void decode() { return; } + mylog(boost::format("encoding: %1% - length: %2% - symbols: %3%") + % ofdm.encoding % tx.psdu_size % tx.n_sym); + // create PDU pmt::pmt_t blob = pmt::make_blob(out_bytes + 2, tx.psdu_size - 4); pmt::pmt_t enc = pmt::from_uint64(ofdm.encoding); @@ -128,36 +199,38 @@ void decode() { } 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); - - } - } + cvec symbols; + symbols.set_length(tx.n_sym * 48); + for(int i = 0; i < tx.n_sym * 48; i++) { + symbols[i] = std::complex(sym[i]); } + + switch(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() { @@ -191,21 +264,20 @@ void decode_conv() { bmat puncture_matrix; switch(ofdm.encoding) { - case 0: - case 2: + case BPSK_1_2: + case QPSK_1_2: + case QAM16_1_2: puncture_matrix = "1 1; 1 1"; break; - case 1: - case 3: + 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 4: - case 5: - case 6: - case 7: + case QAM64_2_3: + puncture_matrix = "1 1 1 1 1 1; 1 0 1 0 1 0;"; break; - default: - assert(false); } code.set_puncture_matrix(puncture_matrix); code.set_truncation_length(30); @@ -221,7 +293,6 @@ void decode_conv() { //dout << "length decoded " << decoded_bits.size() << std::endl; //std::cout << decoded_bits << std::endl; - // } void descramble () { @@ -276,21 +347,27 @@ void print_output() { private: gr_complex sym[1000 * 48 * 100]; - double bits[1000 * 48]; + 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 tx; ofdm_param ofdm; int copied; static int scrambler_init[128]; + + Modulator > bpsk; + Modulator > qpsk; + Modulator > qam16; + Modulator > qam64; }; ofdm_decode_mac::sptr -ofdm_decode_mac::make(bool debug) { - return gnuradio::get_initial_sptr(new ofdm_decode_mac_impl(debug)); +ofdm_decode_mac::make(bool log, bool debug) { + return gnuradio::get_initial_sptr(new ofdm_decode_mac_impl(log, debug)); } int ofdm_decode_mac_impl::scrambler_init[128] = { diff --git a/lib/ofdm_decode_signal.cc b/lib/ofdm_decode_signal.cc index 2bc426b..54ceb11 100644 --- a/lib/ofdm_decode_signal.cc +++ b/lib/ofdm_decode_signal.cc @@ -16,8 +16,8 @@ */ #include #include +#include "utils.h" -#include #include using namespace gr::ieee802_11; @@ -26,12 +26,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) : block("ofdm_decode_signal", +ofdm_decode_signal_impl(bool log, bool debug) : block("ofdm_decode_signal", gr::io_signature::make(1, 1, 48 * sizeof(gr_complex)), gr::io_signature::make(1, 1, 48 * sizeof(gr_complex))), + d_log(log), d_debug(debug), d_copy_symbols(0) { @@ -195,6 +194,9 @@ bool print_signal() { return false; } + mylog(boost::format("encoding: %1% - length: %2% - symbols: %3%") + % d_encoding % d_len % d_copy_symbols); + dout << "d_copy_symbols: " << d_copy_symbols << std::endl; dout << "length: " << d_len << std::endl; return true; @@ -203,6 +205,7 @@ bool print_signal() { private: int d_len; int d_encoding; + bool d_log; bool d_debug; double bits[48]; int d_copy_symbols; @@ -211,8 +214,8 @@ private: }; ofdm_decode_signal::sptr -ofdm_decode_signal::make(bool debug) { - return gnuradio::get_initial_sptr(new ofdm_decode_signal_impl(debug)); +ofdm_decode_signal::make(bool log, bool debug) { + return gnuradio::get_initial_sptr(new ofdm_decode_signal_impl(log, 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}; diff --git a/lib/ofdm_equalize_symbols.cc b/lib/ofdm_equalize_symbols.cc index 6d7c4c8..d0db549 100644 --- a/lib/ofdm_equalize_symbols.cc +++ b/lib/ofdm_equalize_symbols.cc @@ -15,17 +15,15 @@ * along with this program. If not, see . */ #include -#include -#include +#include "utils.h" +#include 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) : block("ofdm_equalize_symbols", gr::io_signature::make(1, 1, 64 * sizeof(gr_complex)), @@ -65,6 +63,10 @@ int general_work (int noutput_items, gr_vector_int& ninput_items, gr_complex p = POLARITY[index]; index++; + // FIXME: think about this... average over amplitude or power + double avg_mag = (abs(in[11]) + abs(in[25]) + abs(in[39]) + abs(in[53])) / 4; + + 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; @@ -83,7 +85,8 @@ int general_work (int noutput_items, gr_vector_int& ninput_items, 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)); + // FIXME: think about this... square or not + out[o] = in[n] * exp(gr_complex(0, -n * beta - alpha)) * gr_complex(1 / avg_mag, 0); o++; } } diff --git a/lib/ofdm_freq_est.cc b/lib/ofdm_freq_est.cc new file mode 100644 index 0000000..b45f0f1 --- /dev/null +++ b/lib/ofdm_freq_est.cc @@ -0,0 +1,64 @@ +/* + * 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 + +using namespace gr::ieee802_11; + + +class ofdm_freq_est_impl : public ofdm_freq_est { + +public: +ofdm_freq_est_impl(bool log, bool debug) : block("ofdm_freq_est", + gr::io_signature::make2(2, 2, sizeof(gr_complex), sizeof(gr_complex)), + gr::io_signature::make(1, 1, sizeof(gr_complex))), + d_log(log), + d_debug(debug), + d_state(SYNC) { + + set_tag_propagation_policy(block::TPP_DONT); +} + +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]; + gr_complex *out = (gr_complex*)output_items[0]; + + + return 0; +} + +void forecast (int noutput_items, gr_vector_int &ninput_items_required) { + ninput_items_required[0] = noutput_items; +} + +private: + enum {SYNC, COPY, RESET} d_state; + std::vector d_tags; + + const bool d_log; + const bool d_debug; +}; + +ofdm_freq_est::sptr +ofdm_freq_est::make(bool log, bool debug) { + return gnuradio::get_initial_sptr(new ofdm_freq_est_impl(log, debug)); +} + diff --git a/lib/ofdm_mac.cc b/lib/ofdm_mac.cc new file mode 100644 index 0000000..f58b118 --- /dev/null +++ b/lib/ofdm_mac.cc @@ -0,0 +1,171 @@ +/* + * 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 +#include + +#include "utils.h" + +#include + +#include +#include +#include + +using namespace gr::ieee802_11; + +class ofdm_mac_impl : public ofdm_mac { + +public: + +ofdm_mac_impl() : + block("ofdm_mac", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(0, 0, 0)), + d_seq_nr(0) { + + message_port_register_out(pmt::mp("phy out")); + message_port_register_out(pmt::mp("app out")); + + message_port_register_in(pmt::mp("app in")); + set_msg_handler(pmt::mp("app in"), boost::bind(&ofdm_mac_impl::app_in, this, _1)); + + message_port_register_in(pmt::mp("phy in")); + set_msg_handler(pmt::mp("phy in"), boost::bind(&ofdm_mac_impl::phy_in, this, _1)); +} + +void phy_in (pmt::pmt_t msg) { + message_port_pub(pmt::mp("app out"), msg); +} + +void app_in (pmt::pmt_t msg) { + + size_t msg_len; + const char *msdu; + + if(pmt::is_eof_object(msg)) { + message_port_pub(pmt::mp("phy out"), pmt::PMT_EOF); + detail().get()->set_done(true); + return; + + } else if(pmt::is_symbol(msg)) { + + std::string str; + str = pmt::symbol_to_string(msg); + msg_len = str.length(); + msdu = str.data(); + + } else if(pmt::is_pair(msg)) { + + msg_len = pmt::blob_length(pmt::cdr(msg)); + msdu = reinterpret_cast(pmt::blob_data(pmt::cdr(msg))); + + } else { + throw std::invalid_argument("OFDM MAC expects PDUs or strings"); + return; + } + + // make MAC frame + int psdu_length; + char *psdu; + generate_mac_data_frame(msdu, msg_len, &psdu, &psdu_length); + + // dict + pmt::pmt_t dict = pmt::make_dict(); + dict = pmt::dict_add(dict, pmt::mp("crc_included"), pmt::PMT_T); + + // blob + pmt::pmt_t mac = pmt::make_blob(psdu, psdu_length); + + // pdu + message_port_pub(pmt::mp("phy out"), pmt::cons(dict, mac)); + + free(psdu); +} + +void generate_mac_data_frame(const char *msdu, int msdu_size, char **psdu, int *psdu_size) { + + //mac frame + MAC_DATAFRAME_HEADER header; + //frame check sequence + unsigned int fcs; + + // TODO: change this back to 0x08 + header.frame_control[0] = 0x08;//0x20; //00000100 00100000 indicate DATA frame (LOL, not), to_ds, from_ds, more frag, retry + header.frame_control[1] = 0x00;//0x40; //all other flags, unutilized //00000010 01000000 + + header.duration[0] = 0x00; //TODO: set accordingly to payload + header.duration[1] = 0x2e; //0x74; //2e = 00101110 -> 01110100 -> 74 + + header.address1[0] = 0x30; + header.address1[1] = 0x14; + header.address1[2] = 0x4a; + header.address1[3] = 0xe6; + header.address1[4] = 0x46; + header.address1[5] = 0xe4; + + header.address2[0] = 0x12; + header.address2[1] = 0x34; + header.address2[2] = 0x56; + header.address2[3] = 0x78; + header.address2[4] = 0x90; + header.address2[5] = 0xab; + + header.address3[0] = 0x42; + header.address3[1] = 0x42; + header.address3[2] = 0x42; + header.address3[3] = 0x42; + header.address3[4] = 0x42; + header.address3[5] = 0x42; + + header.sequence = 0; + for (int i = 0; i < 12; i++) { + if(d_seq_nr & (1 << i)) { + header.sequence |= (1 << (i + 4)); + } + } + header.sequence = htole16(header.sequence); + d_seq_nr++; + + //header size is 24, plus 4 for FCS means 28 bytes + *psdu_size = 28 + msdu_size; + *psdu = (char *) calloc(*psdu_size, sizeof(char)); + + //copy mac header into psdu + std::memcpy(*psdu, &header, 24); + //copy msdu into psdu + memcpy(*psdu + 24, msdu, msdu_size); + //compute and store fcs + boost::crc_32_type result; + result.process_bytes(*psdu, msdu_size + 24); + fcs = result.checksum(); + memcpy(*psdu + msdu_size + 24, &fcs, sizeof(unsigned int)); +} + +private: + uint16_t d_seq_nr; + char d_mac1[6]; + char d_mac2[6]; + char d_mac3[6]; +}; + +ofdm_mac::sptr +ofdm_mac::make() { + return gnuradio::get_initial_sptr(new ofdm_mac_impl()); +} + diff --git a/lib/ofdm_mapper.cc b/lib/ofdm_mapper.cc new file mode 100644 index 0000000..43e9065 --- /dev/null +++ b/lib/ofdm_mapper.cc @@ -0,0 +1,289 @@ +/* + * 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 + +using namespace gr::ieee802_11; + + +class ofdm_mapper_impl : public ofdm_mapper { +public: + +static const int DATA_CARRIERS = 48; + +ofdm_mapper_impl(Encoding e, bool debug) : + block ("ofdm_mapper", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(1, 1, DATA_CARRIERS * sizeof(gr_complex))), + d_symbols_offset(0), + d_symbols(NULL), + d_debug(debug), + d_ofdm(e) { + + message_port_register_in(pmt::mp("in")); + set_encoding(e); +} + +~ofdm_mapper_impl() { + free(d_symbols); +} + +void print_message(const char *msg, size_t len) { + + dout << std::hex << "OFDM MAPPER input symbols" << std::endl + << "===========================" << std::endl; + + for(int i = 0; i < len; i++) { + dout << std::hex << (int)msg[i] << " "; + } + + dout << std::dec << std::endl; +} + +void map_to_symbols(const char *bits, size_t len) { + + dout << "OFDM MAPPER complex symbols" << std::endl + << "===========================" << std::endl; + + for(int i = 0; i < len; i++) { + + // the signal field is bpsk encoded + d_symbols[i] = (i < 48) ? bpsk_mapping[bits[i]] : mapping[bits[i]]; + dout << d_symbols[i] << " "; + } + dout << std::endl; +} + +int general_work(int noutput, gr_vector_int& ninput_items, + gr_vector_const_void_star& input_items, + gr_vector_void_star& output_items ) { + + gr_complex *out = (gr_complex*)output_items[0]; + dout << "OFDM MAPPER called offset: " << d_symbols_offset << + " length: " << d_symbols_len << std::endl; + + while(!d_symbols_offset) { + pmt::pmt_t msg(delete_head_blocking(pmt::intern("in"))); + + if(pmt::is_eof_object(msg)) { + dout << "MAPPER: exiting" << std::endl; + return -1; + } + + if(pmt::is_pair(msg)) { + dout << "OFDM MAPPER: received new message" << std::endl; + gr::thread::scoped_lock lock(d_mutex); + + int psdu_length = pmt::blob_length(pmt::cdr(msg)); + const char *psdu = static_cast(pmt::blob_data(pmt::cdr(msg))); + + + // ############ INSERT MAC STUFF + tx_param tx(d_ofdm, psdu_length); + //tx.print_out(); + //ofdm.print_out(); + + //alloc memory for modulation steps + char *data_bits = (char*)calloc(tx.n_data, sizeof(char)); + char *scrambled_data = (char*)calloc(tx.n_data, sizeof(char)); + char *encoded_data = (char*)calloc(tx.n_data * 2, sizeof(char)); + char *punctured_data = (char*)calloc(tx.n_encoded_bits, sizeof(char)); + char *interleaved_data = (char*)calloc(tx.n_encoded_bits, sizeof(char)); + char *symbols = (char*)calloc((tx.n_encoded_bits / d_ofdm.n_bpsc) + 48, sizeof(char)); + + //generate the OFDM data field, adding service field and pad bits + generate_bits(psdu, data_bits, tx); + //print_hex_array(data_bits, tx.n_data); + + // first step, scrambling + scramble(data_bits, scrambled_data, tx, 23); + //print_hex_array(scrambled_data, tx.n_data); + // reset tail bits + reset_tail_bits(scrambled_data, tx); + //print_hex_array(scrambled_data, tx.n_data); + // encoding + convolutional_encoding(scrambled_data, encoded_data, tx); + //print_hex_array(encoded_data, tx.n_data * 2); + // puncturing + puncturing(encoded_data, punctured_data, tx, d_ofdm); + //std::cout << "punctured" << std::endl; + // interleaving + interleave(punctured_data, interleaved_data, tx, d_ofdm); + //std::cout << "interleaved" << std::endl; + + split_symbols(interleaved_data, symbols + 48, tx, d_ofdm); + //std::cout << "split" << std::endl; + generate_signal_field(symbols, tx, d_ofdm); + //std::cout << "signal" << std::endl; + + d_symbols_len = (tx.n_sym + 1) * 48; + assert(d_symbols_len % 48 == 0); + + + // ############ INSERT MAC STUFF + + d_symbols = static_cast(std::malloc(d_symbols_len * sizeof(gr_complex))); + + + print_message(static_cast(symbols), d_symbols_len); + map_to_symbols(static_cast(symbols), d_symbols_len); + + + + // add tag to indicate start of odfm frame + const pmt::pmt_t key = pmt::string_to_symbol("ofdm_start"); + const pmt::pmt_t value = pmt::from_uint64((d_symbols_len / DATA_CARRIERS)); + const pmt::pmt_t srcid = pmt::string_to_symbol(this->name()); + add_item_tag(0, this->nitems_written(0), key, value, srcid); + + + free(data_bits); + free(scrambled_data); + free(encoded_data); + free(punctured_data); + free(interleaved_data); + free(symbols); + + break; + } + } + + int i = 0; + while(i < noutput) { + + memcpy(out, d_symbols + d_symbols_offset, DATA_CARRIERS * sizeof(gr_complex)); + + i++; + d_symbols_offset += DATA_CARRIERS; + out += DATA_CARRIERS; + + if(d_symbols_offset == d_symbols_len) { + d_symbols_offset = 0; + free(d_symbols); + break; + } + } + + dout << "OFDM MAPPER: output size: " << noutput << + " produced items: " << i << std::endl; + return i; +} + +void set_encoding(Encoding encoding) { + + std::cout << "OFDM MAPPER: encoding: " << encoding << std::endl; + gr::thread::scoped_lock lock(d_mutex); + + d_ofdm = ofdm_param(encoding); + + switch (encoding) { + case BPSK_1_2: + case BPSK_3_4: + mapping = bpsk_mapping; + break; + + case QPSK_1_2: + case QPSK_3_4: + mapping = qpsk_mapping; + break; + + case QAM16_1_2: + case QAM16_3_4: + mapping = qam16_mapping; + break; + + case QAM64_2_3: + case QAM64_3_4: + mapping = qam64_mapping; + break; + + default: + throw std::invalid_argument("wrong encoding"); + break; + } +} + +private: + bool d_debug; + gr_complex* d_symbols; + int d_symbols_offset; + int d_symbols_len; + ofdm_param d_ofdm; + gr::thread::mutex d_mutex; + + const gr_complex *mapping; + static const gr_complex bpsk_mapping[2]; + static const gr_complex qpsk_mapping[4]; + static const gr_complex qam16_mapping[16]; + static const gr_complex qam64_mapping[64]; +}; + +// constellations for different modulations (normalized to avg power 1) +const gr_complex ofdm_mapper_impl::bpsk_mapping[2] = { + gr_complex(-1.0, 0.0), gr_complex(1.0, 0.0)}; +const gr_complex ofdm_mapper_impl::qpsk_mapping[4] = { + gr_complex(-0.7071, -0.7071), gr_complex(-0.7071, 0.7071), + gr_complex(+0.7071, -0.7071), gr_complex(+0.7071, 0.7071)}; +const gr_complex ofdm_mapper_impl::qam16_mapping[16] = { + gr_complex(-0.9487, -0.9487), gr_complex(-0.9487, -0.3162), + gr_complex(-0.9487, 0.9487), gr_complex(-0.9487, 0.3162), + gr_complex(-0.3162, -0.9487), gr_complex(-0.3162, -0.3162), + gr_complex(-0.3162, 0.9487), gr_complex(-0.3162, 0.3162), + gr_complex(0.9487, -0.9487), gr_complex(0.9487, -0.3162), + gr_complex(0.9487, 0.9487), gr_complex(0.9487, 0.3162), + gr_complex(0.3162, -0.9487), gr_complex(0.3162, -0.3162), + gr_complex(0.3162, 0.9487), gr_complex(0.3162, 0.3162)}; +const gr_complex ofdm_mapper_impl::qam64_mapping[64] = { + gr_complex(-1.0801, -1.0801), gr_complex(-1.0801, -0.7715), + gr_complex(-1.0801, -0.1543), gr_complex(-1.0801, -0.4629), + gr_complex(-1.0801, 1.0801), gr_complex(-1.0801, 0.7715), + gr_complex(-1.0801, 0.1543), gr_complex(-1.0801, 0.4629), + gr_complex(-0.7715, -1.0801), gr_complex(-0.7715, -0.7715), + gr_complex(-0.7715, -0.1543), gr_complex(-0.7715, -0.4629), + gr_complex(-0.7715, 1.0801), gr_complex(-0.7715, 0.7715), + gr_complex(-0.7715, 0.1543), gr_complex(-0.7715, 0.4629), + gr_complex(-0.1543, -1.0801), gr_complex(-0.1543, -0.7715), + gr_complex(-0.1543, -0.1543), gr_complex(-0.1543, -0.4629), + gr_complex(-0.1543, 1.0801), gr_complex(-0.1543, 0.7715), + gr_complex(-0.1543, 0.1543), gr_complex(-0.1543, 0.4629), + gr_complex(-0.4629, -1.0801), gr_complex(-0.4629, -0.7715), + gr_complex(-0.4629, -0.1543), gr_complex(-0.4629, -0.4629), + gr_complex(-0.4629, 1.0801), gr_complex(-0.4629, 0.7715), + gr_complex(-0.4629, 0.1543), gr_complex(-0.4629, 0.4629), + gr_complex(1.0801, -1.0801), gr_complex(1.0801, -0.7715), + gr_complex(1.0801, -0.1543), gr_complex(1.0801, -0.4629), + gr_complex(1.0801, 1.0801), gr_complex(1.0801, 0.7715), + gr_complex(1.0801, 0.1543), gr_complex(1.0801, 0.4629), + gr_complex(0.7715, -1.0801), gr_complex(0.7715, -0.7715), + gr_complex(0.7715, -0.1543), gr_complex(0.7715, -0.4629), + gr_complex(0.7715, 1.0801), gr_complex(0.7715, 0.7715), + gr_complex(0.7715, 0.1543), gr_complex(0.7715, 0.4629), + gr_complex(0.1543, -1.0801), gr_complex(0.1543, -0.7715), + gr_complex(0.1543, -0.1543), gr_complex(0.1543, -0.4629), + gr_complex(0.1543, 1.0801), gr_complex(0.1543, 0.7715), + gr_complex(0.1543, 0.1543), gr_complex(0.1543, 0.4629), + gr_complex(0.4629, -1.0801), gr_complex(0.4629, -0.7715), + gr_complex(0.4629, -0.1543), gr_complex(0.4629, -0.4629), + gr_complex(0.4629, 1.0801), gr_complex(0.4629, 0.7715), + gr_complex(0.4629, 0.1543), gr_complex(0.4629, 0.4629)}; + + +ofdm_mapper::sptr +ofdm_mapper::make(Encoding mcs, bool debug) { + return gnuradio::get_initial_sptr(new ofdm_mapper_impl(mcs, debug)); +} diff --git a/lib/ofdm_parse_mac.cc b/lib/ofdm_parse_mac.cc index c788dc0..d96c4ba 100644 --- a/lib/ofdm_parse_mac.cc +++ b/lib/ofdm_parse_mac.cc @@ -16,6 +16,7 @@ */ #include #include "ofdm_parse_mac_impl.h" +#include "utils.h" #include #include @@ -25,18 +26,15 @@ 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) : +ofdm_parse_mac_impl(bool log, bool debug) : block("ofdm_parse_mac", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)), + d_log(log), 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)); } @@ -48,9 +46,10 @@ ofdm_parse_mac_impl(bool debug) : void parse(pmt::pmt_t msg) { if(pmt::is_eof_object(msg)) { - message_port_pub(pmt::mp("out"), pmt::PMT_EOF); detail().get()->set_done(true); return; + } else if(pmt::is_symbol(msg)) { + return; } msg = pmt::cdr(msg); @@ -58,6 +57,8 @@ void parse(pmt::pmt_t msg) { int data_len = pmt::blob_length(msg); mac_header *h = (mac_header*)pmt::blob_data(msg); + mylog(boost::format("length: %1%") % data_len ); + dout << std::endl << "new mac frame (length " << data_len << ")" << std::endl; dout << "=========================================" << std::endl; if(data_len < 20) { @@ -68,7 +69,6 @@ void parse(pmt::pmt_t msg) { 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: @@ -99,15 +99,9 @@ void parse(pmt::pmt_t msg) { // DATA if((((h->frame_control) >> 2) & 63) == 2) { print_ascii(frame + 24, data_len - 24); - pmt::pmt_t payload = pmt::make_blob(frame + 24, data_len - 24); - - message_port_pub(pmt::mp("out"), pmt::cons(pmt::PMT_NIL, payload)); // QoS Data } else if((((h->frame_control) >> 2) & 63) == 34) { print_ascii(frame + 26, data_len - 26); - pmt::pmt_t payload = pmt::make_blob(frame + 26, data_len - 26); - - message_port_pub(pmt::mp("out"), pmt::cons(pmt::PMT_NIL, payload)); } } @@ -346,13 +340,14 @@ void print_ascii(char* buf, int length) { } private: + bool d_log; bool d_debug; }; ofdm_parse_mac::sptr -ofdm_parse_mac::make(bool debug) { - return gnuradio::get_initial_sptr(new ofdm_parse_mac_impl(debug)); +ofdm_parse_mac::make(bool log, bool debug) { + return gnuradio::get_initial_sptr(new ofdm_parse_mac_impl(log, debug)); } diff --git a/lib/ofdm_pilot.cc b/lib/ofdm_pilot.cc new file mode 100644 index 0000000..99e47c0 --- /dev/null +++ b/lib/ofdm_pilot.cc @@ -0,0 +1,136 @@ +/* + * 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 + +using namespace gr::ieee802_11; + + +class ofdm_pilot_impl : public ofdm_pilot { + +static const int TONES = 48; +static const int FFT_SIZE = 64; + +public: + +ofdm_pilot_impl(bool debug) : + sync_block ("ofdm_pilot", + gr::io_signature::make(1, 1, TONES * sizeof(gr_complex)), + gr::io_signature::make(1, 1, FFT_SIZE * sizeof(gr_complex))), + d_offset(0), + d_debug(debug) { + +} + +~ofdm_pilot_impl() { + +} + +int work (int noutput_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 count = 0; + const uint64_t nread = nitems_read(0); + std::vector tags; + + while (count < noutput_items) { + + get_tags_in_range(tags, 0, nread + count, nread + count + 1, pmt::string_to_symbol("ofdm_start")); + + if(tags.size()) { + d_offset = 0; + dout << "OFDM PILOT: start of OFDM frame" << std::endl; + } + + // guard band + memset(out, 0, 6 * sizeof(gr_complex)); + + // subcarriers -26 to -22 + memcpy(out + 6, in, 5 * sizeof(gr_complex)); + + // pilot 1 + out[11] = POLARITY[d_offset]; + + // subcarriers -20 to -8 + memcpy(out + 12, in + 5, 13 * sizeof(gr_complex)); + + // pilot 2 + out[25] = POLARITY[d_offset]; + + // subcarriers -6 to -1 + memcpy(out + 26, in + 18, 6 * sizeof(gr_complex)); + + // DC + out[32] = 0; + + // subcarriers 1 to 6 + memcpy(out + 33, in + 24, 6 * sizeof(gr_complex)); + + // pilot 3 + out[39] = POLARITY[d_offset]; + + // pubcarriers 8 to 20 + memcpy(out + 40, in + 30, 13 * sizeof(gr_complex)); + + // pilot 4 + out[53] = -POLARITY[d_offset]; + + // subcarriers 22 to 26 + memcpy(out + 54, in + 43, 5 * sizeof(gr_complex)); + + // guard band + memset(out + 59, 0, 5 * sizeof(gr_complex)); + + + count++; + out += FFT_SIZE; + in += TONES; + d_offset = (d_offset + 1) % 127; + } + + dout << "OFDM PILOT: produced items: " << noutput_items << std::endl; + + return noutput_items; +} + +private: + bool d_debug; + int d_offset; + static const gr_complex POLARITY[127]; +}; + +const gr_complex ofdm_pilot_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_pilot::sptr +ofdm_pilot::make(bool debug) { + return gnuradio::get_initial_sptr(new ofdm_pilot_impl(debug)); +} + diff --git a/lib/ofdm_preamble.cc b/lib/ofdm_preamble.cc new file mode 100644 index 0000000..f9fd4bb --- /dev/null +++ b/lib/ofdm_preamble.cc @@ -0,0 +1,272 @@ +/* + * 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 + +using namespace gr::ieee802_11; + + +class ofdm_preamble_impl : public ofdm_preamble { + +static const int SYMBOL_LENGTH = 80; + +public: +ofdm_preamble_impl(bool debug) : block("ofdm_preamble", + gr::io_signature::make(1, 1, sizeof(gr_complex)), + gr::io_signature::make(1, 1, sizeof(gr_complex))), + d_debug(debug), + d_state(IDLE) { + + set_relative_rate(1); + set_output_multiple(SYMBOL_LENGTH); + set_tag_propagation_policy(block::TPP_DONT); +} + +~ofdm_preamble_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) { + + int ninput = ninput_items[0] / SYMBOL_LENGTH; + //assert(ninput_items[0] % SYMBOL_LENGTH == 0); + int noutput = noutput_items / SYMBOL_LENGTH; + + const gr_complex *in = (const gr_complex*)input_items[0]; + gr_complex *out = (gr_complex*)output_items[0]; + + int written = 0; + int consumed = 0; + + const uint64_t nread = this->nitems_read(0); + std::vector tags; + pmt::pmt_t key = pmt::string_to_symbol("tx_sob"); + pmt::pmt_t srcid = pmt::string_to_symbol(this->name()); + + dout << "OFDM PREAMBLE: input size: " << ninput_items[0] << " output size: " + << noutput_items << std::endl; + + while(written < noutput) { + + // debug + dout << "OFDM PREAMBLE: iteration - consumed: " << consumed << + " written:" << written << std::endl; + //assert((consumed + 1) * SYMBOL_LENGTH <= ninput_items[0]); + + switch(d_state) { + + case IDLE: + + if(consumed >= ninput) { + goto out; + } + + dout << "OFDM PREAMBLE: start of new frame" << std::endl; + + get_tags_in_range(tags, 0, nread + consumed * SYMBOL_LENGTH, + nread + (consumed + 1) * SYMBOL_LENGTH - 1, + pmt::string_to_symbol("ofdm_start")); + + // looks like we changed to modulation scheme during the frame + if(tags.size() != 1) { + std::cout << "PREAMBLE: frame is longer than expected" << std::endl; + throw std::runtime_error("PREAMBLE: frame is too long"); + break; + } + d_frame_left = pmt::to_uint64(tags[0].value); + d_preamble_left = 4; + d_state = PRE; + + // add tag to indicate start of odfm frame + add_item_tag(0, this->nitems_written(0) + written * SYMBOL_LENGTH, key, pmt::PMT_T, srcid); + + // FALL THROUGH !!!!! + + case PRE: + + dout << "OFDM PREAMBLE: copy preamble" << std::endl; + + memcpy(out, PREAMBLE + (4 - d_preamble_left) * SYMBOL_LENGTH, + SYMBOL_LENGTH * sizeof(gr_complex)); + + out += SYMBOL_LENGTH; + written++; + d_preamble_left--; + + if(!d_preamble_left) { + d_state = FRAME; + } + + break; + + case FRAME: + if(consumed >= ninput) { + goto out; + } + + dout << "OFDM PREAMBLE: copy frame" << std::endl; + + memcpy(out, in, SYMBOL_LENGTH * sizeof(gr_complex)); + + consumed++; + in += SYMBOL_LENGTH; + out += SYMBOL_LENGTH; + written++; + d_frame_left--; + + if(!d_frame_left) { + d_state = IDLE; + insert_eob(nitems_written(0) + written * SYMBOL_LENGTH -1); + goto out; + } + + break; + + default: + assert(false); + break; + } + } + +out: + + dout << "PREAMBLE: consumed " << consumed * SYMBOL_LENGTH; + dout << " written " << written * SYMBOL_LENGTH << std::endl; + consume(0, consumed * SYMBOL_LENGTH); + return written * SYMBOL_LENGTH; +} + +void insert_eob(uint64_t item) { + dout << "OFDM PAD: insert eob at: " << item << std::endl; + + const pmt::pmt_t eob_key = pmt::string_to_symbol("tx_eob"); + const pmt::pmt_t value = pmt::PMT_T; + const pmt::pmt_t srcid = pmt::string_to_symbol(this->name()); + add_item_tag(0, item, eob_key, value, srcid); +} + +void +forecast (int noutput_items, gr_vector_int &ninput_items_required) +{ + if(d_state == PRE) { + ninput_items_required[0] = 0; + } else { + ninput_items_required[0] = noutput_items; + } + + dout << "forecast noutput_items: " << noutput_items << " required: " << ninput_items_required[0] << std::endl; +} + +private: + bool d_debug; + size_t d_preamble_left; + size_t d_frame_left; + enum {IDLE, PRE, FRAME} d_state; + + static gr_complex PREAMBLE[320]; +}; + +ofdm_preamble::sptr +ofdm_preamble::make(bool debug) { + return gnuradio::get_initial_sptr(new ofdm_preamble_impl(debug)); +} + +gr_complex ofdm_preamble_impl::PREAMBLE[320] = { + gr_complex( 0.2041, 0.2041), gr_complex(-1.1755, 0.0208), gr_complex(-0.1196, -0.6969), gr_complex( 1.2670, -0.1123), + gr_complex( 0.8165, 0.0000), gr_complex( 1.2670, -0.1123), gr_complex(-0.1196, -0.6969), gr_complex(-1.1755, 0.0208), + gr_complex( 0.4082, 0.4082), gr_complex( 0.0208, -1.1755), gr_complex(-0.6969, -0.1196), gr_complex(-0.1123, 1.2670), + gr_complex( 0.0000, 0.8165), gr_complex(-0.1123, 1.2670), gr_complex(-0.6969, -0.1196), gr_complex( 0.0208, -1.1755), + gr_complex( 0.4082, 0.4082), gr_complex(-1.1755, 0.0208), gr_complex(-0.1196, -0.6969), gr_complex( 1.2670, -0.1123), + gr_complex( 0.8165, 0.0000), gr_complex( 1.2670, -0.1123), gr_complex(-0.1196, -0.6969), gr_complex(-1.1755, 0.0208), + gr_complex( 0.4082, 0.4082), gr_complex( 0.0208, -1.1755), gr_complex(-0.6969, -0.1196), gr_complex(-0.1123, 1.2670), + gr_complex( 0.0000, 0.8165), gr_complex(-0.1123, 1.2670), gr_complex(-0.6969, -0.1196), gr_complex( 0.0208, -1.1755), + gr_complex( 0.4082, 0.4082), gr_complex(-1.1755, 0.0208), gr_complex(-0.1196, -0.6969), gr_complex( 1.2670, -0.1123), + gr_complex( 0.8165, 0.0000), gr_complex( 1.2670, -0.1123), gr_complex(-0.1196, -0.6969), gr_complex(-1.1755, 0.0208), + gr_complex( 0.4082, 0.4082), gr_complex( 0.0208, -1.1755), gr_complex(-0.6969, -0.1196), gr_complex(-0.1123, 1.2670), + gr_complex( 0.0000, 0.8165), gr_complex(-0.1123, 1.2670), gr_complex(-0.6969, -0.1196), gr_complex( 0.0208, -1.1755), + gr_complex( 0.4082, 0.4082), gr_complex(-1.1755, 0.0208), gr_complex(-0.1196, -0.6969), gr_complex( 1.2670, -0.1123), + gr_complex( 0.8165, 0.0000), gr_complex( 1.2670, -0.1123), gr_complex(-0.1196, -0.6969), gr_complex(-1.1755, 0.0208), + gr_complex( 0.4082, 0.4082), gr_complex( 0.0208, -1.1755), gr_complex(-0.6969, -0.1196), gr_complex(-0.1123, 1.2670), + gr_complex( 0.0000, 0.8165), gr_complex(-0.1123, 1.2670), gr_complex(-0.6969, -0.1196), gr_complex( 0.0208, -1.1755), + gr_complex( 0.4082, 0.4082), gr_complex(-1.1755, 0.0208), gr_complex(-0.1196, -0.6969), gr_complex( 1.2670, -0.1123), + gr_complex( 0.8165, 0.0000), gr_complex( 1.2670, -0.1123), gr_complex(-0.1196, -0.6969), gr_complex(-1.1755, 0.0208), + gr_complex( 0.4082, 0.4082), gr_complex( 0.0208, -1.1755), gr_complex(-0.6969, -0.1196), gr_complex(-0.1123, 1.2670), + gr_complex( 0.0000, 0.8165), gr_complex(-0.1123, 1.2670), gr_complex(-0.6969, -0.1196), gr_complex( 0.0208, -1.1755), + gr_complex( 0.4082, 0.4082), gr_complex(-1.1755, 0.0208), gr_complex(-0.1196, -0.6969), gr_complex( 1.2670, -0.1123), + gr_complex( 0.8165, 0.0000), gr_complex( 1.2670, -0.1123), gr_complex(-0.1196, -0.6969), gr_complex(-1.1755, 0.0208), + gr_complex( 0.4082, 0.4082), gr_complex( 0.0208, -1.1755), gr_complex(-0.6969, -0.1196), gr_complex(-0.1123, 1.2670), + gr_complex( 0.0000, 0.8165), gr_complex(-0.1123, 1.2670), gr_complex(-0.6969, -0.1196), gr_complex( 0.0208, -1.1755), + gr_complex( 0.4082, 0.4082), gr_complex(-1.1755, 0.0208), gr_complex(-0.1196, -0.6969), gr_complex( 1.2670, -0.1123), + gr_complex( 0.8165, 0.0000), gr_complex( 1.2670, -0.1123), gr_complex(-0.1196, -0.6969), gr_complex(-1.1755, 0.0208), + gr_complex( 0.4082, 0.4082), gr_complex( 0.0208, -1.1755), gr_complex(-0.6969, -0.1196), gr_complex(-0.1123, 1.2670), + gr_complex( 0.0000, 0.8165), gr_complex(-0.1123, 1.2670), gr_complex(-0.6969, -0.1196), gr_complex( 0.0208, -1.1755), + gr_complex( 0.4082, 0.4082), gr_complex(-1.1755, 0.0208), gr_complex(-0.1196, -0.6969), gr_complex( 1.2670, -0.1123), + gr_complex( 0.8165, 0.0000), gr_complex( 1.2670, -0.1123), gr_complex(-0.1196, -0.6969), gr_complex(-1.1755, 0.0208), + gr_complex( 0.4082, 0.4082), gr_complex( 0.0208, -1.1755), gr_complex(-0.6969, -0.1196), gr_complex(-0.1123, 1.2670), + gr_complex( 0.0000, 0.8165), gr_complex(-0.1123, 1.2670), gr_complex(-0.6969, -0.1196), gr_complex( 0.0208, -1.1755), + gr_complex( 0.4082, 0.4082), gr_complex(-1.1755, 0.0208), gr_complex(-0.1196, -0.6969), gr_complex( 1.2670, -0.1123), + gr_complex( 0.8165, 0.0000), gr_complex( 1.2670, -0.1123), gr_complex(-0.1196, -0.6969), gr_complex(-1.1755, 0.0208), + gr_complex( 0.4082, 0.4082), gr_complex( 0.0208, -1.1755), gr_complex(-0.6969, -0.1196), gr_complex(-0.1123, 1.2670), + gr_complex( 0.0000, 0.8165), gr_complex(-0.1123, 1.2670), gr_complex(-0.6969, -0.1196), gr_complex( 0.0208, -1.1755), + gr_complex( 0.4082, 0.4082), gr_complex(-1.1755, 0.0208), gr_complex(-0.1196, -0.6969), gr_complex( 1.2670, -0.1123), + gr_complex( 0.8165, 0.0000), gr_complex( 1.2670, -0.1123), gr_complex(-0.1196, -0.6969), gr_complex(-1.1755, 0.0208), + gr_complex( 0.4082, 0.4082), gr_complex( 0.0208, -1.1755), gr_complex(-0.6969, -0.1196), gr_complex(-0.1123, 1.2670), + gr_complex( 0.0000, 0.8165), gr_complex(-0.1123, 1.2670), gr_complex(-0.6969, -0.1196), gr_complex( 0.0208, -1.1755), + gr_complex(-0.4893, 0.2041), gr_complex( 0.1090, -0.8662), gr_complex( 0.8140, -0.9396), gr_complex(-0.8155, -1.0218), + gr_complex(-0.0249, -0.4773), gr_complex( 0.6663, 0.6571), gr_complex(-1.1300, 0.1820), gr_complex(-1.0818, 0.1470), + gr_complex(-0.3110, 1.3392), gr_complex(-0.5011, 0.1935), gr_complex(-0.5353, -0.7214), gr_complex( 0.6173, -0.1253), + gr_complex( 0.7297, -0.8197), gr_complex(-1.1650, -0.5789), gr_complex(-0.5077, -0.3488), gr_complex( 0.3277, -0.8728), + gr_complex( 0.5547, 0.5547), gr_complex( 1.0583, 0.0363), gr_complex(-0.1995, -1.4259), gr_complex( 0.5207, 0.1326), + gr_complex( 0.2172, 0.5195), gr_complex(-1.2142, 0.4205), gr_complex( 0.0088, 1.0207), gr_complex( 0.4734, -0.0362), + gr_complex( 0.8657, 0.2298), gr_complex(-0.3401, 0.9423), gr_complex(-1.0218, 0.4897), gr_complex( 0.5309, 0.7784), + gr_complex( 0.1874, -0.2475), gr_complex( 0.8594, -0.7348), gr_complex( 0.3528, 0.9865), gr_complex(-0.0455, 1.0679), + gr_complex( 1.3868, 0.0000), gr_complex(-0.0455, -1.0679), gr_complex( 0.3528, -0.9865), gr_complex( 0.8594, 0.7348), + gr_complex( 0.1874, 0.2475), gr_complex( 0.5309, -0.7784), gr_complex(-1.0218, -0.4897), gr_complex(-0.3401, -0.9423), + gr_complex( 0.8657, -0.2298), gr_complex( 0.4734, 0.0362), gr_complex( 0.0088, -1.0207), gr_complex(-1.2142, -0.4205), + gr_complex( 0.2172, -0.5195), gr_complex( 0.5207, -0.1326), gr_complex(-0.1995, 1.4259), gr_complex( 1.0583, -0.0363), + gr_complex( 0.5547, -0.5547), gr_complex( 0.3277, 0.8728), gr_complex(-0.5077, 0.3488), gr_complex(-1.1650, 0.5789), + gr_complex( 0.7297, 0.8197), gr_complex( 0.6173, 0.1253), gr_complex(-0.5353, 0.7214), gr_complex(-0.5011, -0.1935), + gr_complex(-0.3110, -1.3392), gr_complex(-1.0818, -0.1470), gr_complex(-1.1300, -0.1820), gr_complex( 0.6663, -0.6571), + gr_complex(-0.0249, 0.4773), gr_complex(-0.8155, 1.0218), gr_complex( 0.8140, 0.9396), gr_complex( 0.1090, 0.8662), + gr_complex(-1.3868, 0.0000), gr_complex( 0.1090, -0.8662), gr_complex( 0.8140, -0.9396), gr_complex(-0.8155, -1.0218), + gr_complex(-0.0249, -0.4773), gr_complex( 0.6663, 0.6571), gr_complex(-1.1300, 0.1820), gr_complex(-1.0818, 0.1470), + gr_complex(-0.3110, 1.3392), gr_complex(-0.5011, 0.1935), gr_complex(-0.5353, -0.7214), gr_complex( 0.6173, -0.1253), + gr_complex( 0.7297, -0.8197), gr_complex(-1.1650, -0.5789), gr_complex(-0.5077, -0.3488), gr_complex( 0.3277, -0.8728), + gr_complex( 0.5547, 0.5547), gr_complex( 1.0583, 0.0363), gr_complex(-0.1995, -1.4259), gr_complex( 0.5207, 0.1326), + gr_complex( 0.2172, 0.5195), gr_complex(-1.2142, 0.4205), gr_complex( 0.0088, 1.0207), gr_complex( 0.4734, -0.0362), + gr_complex( 0.8657, 0.2298), gr_complex(-0.3401, 0.9423), gr_complex(-1.0218, 0.4897), gr_complex( 0.5309, 0.7784), + gr_complex( 0.1874, -0.2475), gr_complex( 0.8594, -0.7348), gr_complex( 0.3528, 0.9865), gr_complex(-0.0455, 1.0679), + gr_complex( 1.3868, 0.0000), gr_complex(-0.0455, -1.0679), gr_complex( 0.3528, -0.9865), gr_complex( 0.8594, 0.7348), + gr_complex( 0.1874, 0.2475), gr_complex( 0.5309, -0.7784), gr_complex(-1.0218, -0.4897), gr_complex(-0.3401, -0.9423), + gr_complex( 0.8657, -0.2298), gr_complex( 0.4734, 0.0362), gr_complex( 0.0088, -1.0207), gr_complex(-1.2142, -0.4205), + gr_complex( 0.2172, -0.5195), gr_complex( 0.5207, -0.1326), gr_complex(-0.1995, 1.4259), gr_complex( 1.0583, -0.0363), + gr_complex( 0.5547, -0.5547), gr_complex( 0.3277, 0.8728), gr_complex(-0.5077, 0.3488), gr_complex(-1.1650, 0.5789), + gr_complex( 0.7297, 0.8197), gr_complex( 0.6173, 0.1253), gr_complex(-0.5353, 0.7214), gr_complex(-0.5011, -0.1935), + gr_complex(-0.3110, -1.3392), gr_complex(-1.0818, -0.1470), gr_complex(-1.1300, -0.1820), gr_complex( 0.6663, -0.6571), + gr_complex(-0.0249, 0.4773), gr_complex(-0.8155, 1.0218), gr_complex( 0.8140, 0.9396), gr_complex( 0.1090, 0.8662), + gr_complex(-1.3868, 0.0000), gr_complex( 0.1090, -0.8662), gr_complex( 0.8140, -0.9396), gr_complex(-0.8155, -1.0218), + gr_complex(-0.0249, -0.4773), gr_complex( 0.6663, 0.6571), gr_complex(-1.1300, 0.1820), gr_complex(-1.0818, 0.1470), + gr_complex(-0.3110, 1.3392), gr_complex(-0.5011, 0.1935), gr_complex(-0.5353, -0.7214), gr_complex( 0.6173, -0.1253), + gr_complex( 0.7297, -0.8197), gr_complex(-1.1650, -0.5789), gr_complex(-0.5077, -0.3488), gr_complex( 0.3277, -0.8728), + gr_complex( 0.5547, 0.5547), gr_complex( 1.0583, 0.0363), gr_complex(-0.1995, -1.4259), gr_complex( 0.5207, 0.1326), + gr_complex( 0.2172, 0.5195), gr_complex(-1.2142, 0.4205), gr_complex( 0.0088, 1.0207), gr_complex( 0.4734, -0.0362), + gr_complex( 0.8657, 0.2298), gr_complex(-0.3401, 0.9423), gr_complex(-1.0218, 0.4897), gr_complex( 0.5309, 0.7784), + gr_complex( 0.1874, -0.2475), gr_complex( 0.8594, -0.7348), gr_complex( 0.3528, 0.9865), gr_complex(-0.0455, 1.0679) + }; diff --git a/lib/ofdm_sync_long.cc b/lib/ofdm_sync_long.cc index 79cbec1..0f53137 100644 --- a/lib/ofdm_sync_long.cc +++ b/lib/ofdm_sync_long.cc @@ -15,40 +15,41 @@ * along with this program. If not, see . */ #include +#include "utils.h" #include #include #include #include #include -#include using namespace gr::ieee802_11; +using namespace std; 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) : block("ofdm_sync_long", +ofdm_sync_long_impl(unsigned int sync_length, bool log, bool debug) : block("ofdm_sync_long", gr::io_signature::make2(2, 2, sizeof(gr_complex), sizeof(gr_complex)), gr::io_signature::make(1, 1, sizeof(gr_complex))), + d_log(log), d_debug(debug), d_offset(0), d_freq_est(0), d_state(SYNC), - SYNC_LENGTH(sync_lenght), - FREQ_EST(freq_est) { + SYNC_LENGTH(sync_length) { set_tag_propagation_policy(block::TPP_DONT); d_fir = new gr::filter::kernel::fir_filter_ccc(1, LONG); d_correlation = gr::fft::malloc_complex(8192); + d_freq_est_buf = static_cast(std::malloc(sync_length * sizeof(gr_complex))); } ~ofdm_sync_long_impl(){ delete d_fir; gr::fft::free(d_correlation); + free(d_freq_est_buf); } int general_work (int noutput, gr_vector_int& ninput_items, @@ -93,9 +94,8 @@ int general_work (int noutput, gr_vector_int& ninput_items, while(i + 63 < ninput) { - if(d_offset < FREQ_EST) { - d_freq_est += in[i] * conj(in[i + 16]); - } + d_freq_est += in[i] * conj(in[i + 16]); + d_freq_est_buf[d_offset] = d_freq_est; d_cor.push_back(std::tuple(abs(d_correlation[i]), d_offset)); @@ -104,8 +104,12 @@ int general_work (int noutput, gr_vector_int& ninput_items, if(d_offset == SYNC_LENGTH) { search_frame_start(); + d_freq_est = d_freq_est_buf[std::max(0, d_frame_start - 160 - 17)]; d_offset = 0; d_state = COPY; + + mylog(boost::format("frame at %1% - freq_est (20M): %2%") % d_frame_start + % ((arg(d_freq_est) / 16) * 20e6 / (2 * M_PI))); break; } } @@ -160,7 +164,7 @@ int general_work (int noutput, gr_vector_int& ninput_items, break; default: - assert(false); + std::runtime_error("bad state"); break; } @@ -173,6 +177,8 @@ int general_work (int noutput, gr_vector_int& ninput_items, void forecast (int noutput_items, gr_vector_int &ninput_items_required) { + // in sync state we need at least a symbol to correlate + // with the pattern if(d_state == SYNC) { ninput_items_required[0] = 64; ninput_items_required[1] = 64; @@ -181,39 +187,38 @@ void forecast (int noutput_items, gr_vector_int &ninput_items_required) { 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() { + // sort list (highest correlation first) assert(d_cor.size() == SYNC_LENGTH); d_cor.sort(); d_cor.reverse(); - std::list>::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; - //} - + // copy list in vector for nicer access + vector> vec(d_cor.begin(), d_cor.end()); d_cor.clear(); + + // in case we don't find anything use SYNC_LENGTH + d_frame_start = SYNC_LENGTH; + + for(int i = 0; i < 3; i++) { + for(int k = i + 1; k < 4; k++) { + int diff = abs(get<1>(vec[i]) - get<1>(vec[k])); + if(diff == 64) { + d_frame_start = max(get<1>(vec[i]), get<1>(vec[k])) + 64; + // nice match found, return immediately + return; + + // TODO: check if these offsets make sense + } else if(diff == 63) { + d_frame_start = max(get<1>(vec[i]), get<1>(vec[k])) + 63; + } else if(diff = 65) { + d_frame_start = max(get<1>(vec[i]), get<1>(vec[k])) + 64; + } + } + } } private: @@ -222,20 +227,21 @@ private: int d_frame_start; gr_complex d_freq_est; gr_complex *d_correlation; + gr_complex *d_freq_est_buf; std::list> d_cor; std::vector d_tags; gr::filter::kernel::fir_filter_ccc *d_fir; + const bool d_log; const bool d_debug; const int SYNC_LENGTH; - const int FREQ_EST; static const std::vector 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)); +ofdm_sync_long::make(unsigned int sync_length, bool log, bool debug) { + return gnuradio::get_initial_sptr(new ofdm_sync_long_impl(sync_length, log, debug)); } const std::vector ofdm_sync_long_impl::LONG = { diff --git a/lib/ofdm_sync_short.cc b/lib/ofdm_sync_short.cc index 7317046..9b3c147 100644 --- a/lib/ofdm_sync_short.cc +++ b/lib/ofdm_sync_short.cc @@ -16,6 +16,7 @@ */ #include #include +#include "utils.h" #include @@ -23,13 +24,12 @@ 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) : block("ofdm_sync_short", + unsigned int min_plateau, bool log, bool debug) : block("ofdm_sync_short", gr::io_signature::make2(2, 2, sizeof(gr_complex), sizeof(float)), gr::io_signature::make(1, 1, sizeof(gr_complex))), + d_log(log), d_debug(debug), d_state(SEARCH), d_plateau(0), @@ -108,7 +108,7 @@ int general_work (int noutput_items, gr_vector_int& ninput_items, } void insert_tag(uint64_t item) { - dout << "SYNC SHORT: insert ofdm_start at: " << item << std::endl; + mylog(boost::format("frame start at %1%") % item); const pmt::pmt_t key = pmt::string_to_symbol("ofdm_start"); const pmt::pmt_t value = pmt::PMT_T; @@ -121,6 +121,7 @@ private: int d_copy_left; int d_plateau; const double d_threshold; + const bool d_log; const bool d_debug; const unsigned int MAX_SAMPLES; const unsigned int MIN_PLATEAU; @@ -128,7 +129,7 @@ private: ofdm_sync_short::sptr ofdm_sync_short::make(double threshold, unsigned int max_samples, - unsigned int min_plateau, bool debug) { + unsigned int min_plateau, bool log, bool debug) { return gnuradio::get_initial_sptr(new ofdm_sync_short_impl(threshold, - max_samples, min_plateau, debug)); + max_samples, min_plateau, log, debug)); } diff --git a/lib/ofdm_utils.cc b/lib/ofdm_utils.cc deleted file mode 100644 index b21443a..0000000 --- a/lib/ofdm_utils.cc +++ /dev/null @@ -1,124 +0,0 @@ -/* - * 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 "ofdm_utils.h" - -#include -#include -#include -#include -#include - - -ofdm_param::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 -ofdm_param::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; -} - -tx_param::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; -} -void -tx_param::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; -} - diff --git a/lib/ofdm_utils.h b/lib/ofdm_utils.h deleted file mode 100644 index 8748e64..0000000 --- a/lib/ofdm_utils.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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 . - */ -#ifndef INCLUDED_IEEE802_11_OFDM_UTILS_H -#define INCLUDED_IEEE802_11_OFDM_UTILS_H - -#include - -/** - * Define structure for the MAC header of a data frame. - * Values as stored as MSB, but standard mandates LSB - * representation. Bit utils functions can help changing - * endiannes - */ -struct MAC_DATAFRAME_HEADER { - char frame_control[2]; //protocol version, type, subtype, to_ds, from_ds, ... - char duration[2]; //duration field - char address1[6]; //address 1 indicating BSSID: 6 bytes MAC address - char address2[6]; //address 2 indicating receiver - char address3[6]; //address 3 indicating sender - char sequence[2]; //sequence number plus fragment number -}; - -enum ENCODING { - BPSK_1_2 = 0, - BPSK_3_4 = 1, - QPSK_1_2 = 2, - QPSK_3_4 = 3, - QAM16_1_2 = 4, - QAM16_3_4 = 5, - QAM64_2_3 = 6, - QAM64_3_4 = 7, -}; - -/** - * OFDM parameters - */ -class ofdm_param { -public: - ofdm_param(ENCODING e); - - // 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; - - void print_out(); -}; - -/** - * packet specific parameters - */ -class tx_param { -public: - tx_param(ofdm_param &ofdm, int psdu_length); - // 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(); -}; - -#endif /* INCLUDED_IEEE802_11_OFDM_UTILS_H */ diff --git a/lib/utils.cc b/lib/utils.cc new file mode 100644 index 0000000..9f73f24 --- /dev/null +++ b/lib/utils.cc @@ -0,0 +1,343 @@ +/* + * 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 "utils.h" + +#include +#include +#include + + +ofdm_param::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 +ofdm_param::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; +} + +tx_param::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; +} +void +tx_param::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; +} + +int get_bit(int b, int i) { + return (b & (1 << i) ? 1 : 0); +} + +void scramble(const char *in, char *out, tx_param &tx, char initial_state) { + + int state = initial_state; + int feedback; + + for (int i = 0; i < tx.n_data; i++) { + + feedback = (!!(state & 64)) ^ (!!(state & 8)); + out[i] = feedback ^ in[i]; + state = ((state << 1) & 0x7e) | feedback; + } +} + +void reset_tail_bits(char *scrambled_data, tx_param &tx) { + memset(scrambled_data + tx.n_data - tx.n_pad - 6, 0, 6 * sizeof(char)); +} + +int ones(int n) { + int sum = 0; + for(int i = 0; i < 8; i++) { + if(n & (1 << i)) { + sum++; + } + } + return sum; +} + +void convolutional_encoding(const char *in, char *out, tx_param &tx) { + + int state = 0; + + for(int i = 0; i < tx.n_data; i++) { + assert(in[i] == 0 || in[i] == 1); + state = ((state << 1) & 0x7e) | in[i]; + out[i * 2] = ones(state & 0155) % 2; + out[i * 2 + 1] = ones(state & 0117) % 2; + } +} + +void puncturing(const char *in, char *out, tx_param &tx, ofdm_param &ofdm) { + + int mod; + + for (int i = 0; i < tx.n_data * 2; i++) { + switch(ofdm.encoding) { + case BPSK_1_2: + case QPSK_1_2: + case QAM16_1_2: + *out = in[i]; + out++; + break; + + case QAM64_2_3: + if (i % 4 != 3) { + *out = in[i]; + out++; + } + break; + + case BPSK_3_4: + case QPSK_3_4: + case QAM16_3_4: + case QAM64_3_4: + mod = i % 6; + if (!(mod == 3 || mod == 4)) { + *out = in[i]; + out++; + } + break; + defaut: + assert(false); + break; + } + } +} + +void interleave(const char *in, char *out, tx_param &tx, ofdm_param &ofdm, bool reverse) { + + int n_cbps = ofdm.n_cbps; + int first[n_cbps]; + int second[n_cbps]; + int s = std::max(ofdm.n_bpsc / 2, 1); + + for(int j = 0; j < n_cbps; j++) { + first[j] = s * (j / s) + ((j + int(floor(16.0 * j / n_cbps))) % s); + } + + for(int i = 0; i < n_cbps; i++) { + second[i] = 16 * i - (n_cbps - 1) * int(floor(16.0 * i / n_cbps)); + } + + for(int i = 0; i < tx.n_sym; i++) { + for(int k = 0; k < n_cbps; k++) { + if(reverse) { + out[i * n_cbps + second[first[k]]] = in[i * n_cbps + k]; + } else { + out[i * n_cbps + k] = in[i * n_cbps + second[first[k]]]; + } + } + } +} + +void interleave(const double *in, double *out, tx_param &tx, ofdm_param &ofdm, bool reverse) { + + int n_cbps = ofdm.n_cbps; + int first[n_cbps]; + int second[n_cbps]; + int s = std::max(ofdm.n_bpsc / 2, 1); + + for(int j = 0; j < n_cbps; j++) { + first[j] = s * (j / s) + ((j + int(floor(16.0 * j / n_cbps))) % s); + } + + for(int i = 0; i < n_cbps; i++) { + second[i] = 16 * i - (n_cbps - 1) * int(floor(16.0 * i / n_cbps)); + } + + for(int i = 0; i < tx.n_sym; i++) { + for(int k = 0; k < n_cbps; k++) { + if(reverse) { + out[i * n_cbps + second[first[k]]] = in[i * n_cbps + k]; + } else { + out[i * n_cbps + k] = in[i * n_cbps + second[first[k]]]; + } + } + } +} +void split_symbols(const char *in, char *out, tx_param &tx, ofdm_param &ofdm) { + + int symbols = tx.n_sym * 48; + + for (int i = 0; i < symbols; i++) { + out[i] = 0; + for(int k = 0; k < ofdm.n_bpsc; k++) { + assert(*in == 1 || *in == 0); + out[i] |= (*in << (ofdm.n_bpsc - k - 1)); + in++; + } + } +} + + +void generate_signal_field(char *out, tx_param &tx, ofdm_param &ofdm) { + + //data bits of the signal header + char *signal_header = (char *) malloc(sizeof(char) * 24); + + //signal header after... + //convolutional encoding + char *encoded_signal_header = (char *) malloc(sizeof(char) * 48); + //interleaving + char *interleaved_signal_header = (char *) malloc(sizeof(char) * 48); + + int length = tx.psdu_size; + + // first 4 bits represent the modulation and coding scheme + signal_header[ 0] = get_bit(ofdm.rate_field, 3); + signal_header[ 1] = get_bit(ofdm.rate_field, 2); + signal_header[ 2] = get_bit(ofdm.rate_field, 1); + signal_header[ 3] = get_bit(ofdm.rate_field, 0); + // 5th bit is reserved and must be set to 0 + signal_header[ 4] = 0; + // then 12 bits represent the length + signal_header[ 5] = get_bit(length, 0); + signal_header[ 6] = get_bit(length, 1); + signal_header[ 7] = get_bit(length, 2); + signal_header[ 8] = get_bit(length, 3); + signal_header[ 9] = get_bit(length, 4); + signal_header[10] = get_bit(length, 5); + signal_header[11] = get_bit(length, 6); + signal_header[12] = get_bit(length, 7); + signal_header[13] = get_bit(length, 8); + signal_header[14] = get_bit(length, 9); + signal_header[15] = get_bit(length, 10); + signal_header[16] = get_bit(length, 11); + //18-th bit is the parity bit for the first 17 bits + int sum = 0; + for(int i = 0; i < 17; i++) { + if(signal_header[i]) { + sum++; + } + } + signal_header[17] = sum % 2; + + // last 6 bits must be set to 0 + for (int i = 0; i < 6; i++) { + signal_header[18 + i] = 0; + } + + ofdm_param signal_ofdm(BPSK_1_2); + tx_param signal_tx(signal_ofdm, 3); + signal_tx.n_data = 24; + signal_tx.n_sym = 1; + + // convolutional encoding (scrambling is not needed) + convolutional_encoding(signal_header, encoded_signal_header, signal_tx); + // interleaving + //interleave(encoded_signal_header, interleaved_signal_header, signal_tx, signal_ofdm); + interleave(encoded_signal_header, out, signal_tx, signal_ofdm); + + free(signal_header); + free(encoded_signal_header); + free(interleaved_signal_header); +} + +void generate_bits(const char *psdu, char *data_bits, tx_param &tx) { + + // first 16 bits are zero (SERVICE/DATA field) + memset(data_bits, 0, 16); + data_bits += 16; + + for(int i = 0; i < tx.psdu_size; i++) { + for(int b = 0; b < 8; b++) { + data_bits[i * 8 + b] = !!(psdu[i] & (1 << b)); + } + } +} diff --git a/lib/utils.h b/lib/utils.h new file mode 100644 index 0000000..ef1d2d0 --- /dev/null +++ b/lib/utils.h @@ -0,0 +1,110 @@ +/* + * 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 . + */ +#ifndef INCLUDED_IEEE802_11_OFDM_UTILS_H +#define INCLUDED_IEEE802_11_OFDM_UTILS_H + +#include +#include +#include +#include + +#define dout d_debug && std::cout +#define mylog(msg) do { if(d_log) *d_logger << log4cpp::Priority::INFO << msg << log4cpp::eol; } while(0); + +struct MAC_DATAFRAME_HEADER { + //protocol version, type, subtype, to_ds, from_ds, ... + char frame_control[2]; + char duration[2]; + char address1[6]; + char address2[6]; + char address3[6]; + uint16_t sequence; +}__attribute__((packed)); + +/** + * OFDM parameters + */ +class ofdm_param { +public: + ofdm_param(Encoding e); + + // 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; + + void print_out(); +}; + +/** + * packet specific parameters + */ +class tx_param { +public: + tx_param(ofdm_param &ofdm, int psdu_length); + // 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(); +}; + +/** + * Given a payload, generates a MAC data frame (i.e., a PSDU) to be given + * to the physical layer for encoding. + * + * \param msdu the payload for the MAC frame + * \param msdu_size the size of the msdu in bytes + * \param psdu pointer to a byte array where to store the MAC frame. Memory + * will be alloced by the function + * \param psdu_size pointer to an integer where the size of the psdu in bytes + * will be stored + * \param seq sequence number of the frame + */ +void generate_mac_data_frame(const char *msdu, int msdu_size, char **psdu, int *psdu_size, char seq); + + +void scramble(const char *input, char *out, tx_param &tx, char initial_state); + +void reset_tail_bits(char *scrambled_data, tx_param &tx); + +void convolutional_encoding(const char *input, char *out, tx_param &tx); + +void puncturing(const char *input, char *out, tx_param &tx, ofdm_param &ofdm); + +void interleave(const char *input, char *out, tx_param &tx, ofdm_param &ofdm, bool reverse = false); +void interleave(const double *input, double *out, tx_param &tx, ofdm_param &ofdm, bool reverse = false); + +void split_symbols(const char *input, char *out, tx_param &tx, ofdm_param &ofdm); + +void generate_signal_field(char *out, tx_param &tx, ofdm_param &ofdm); + +void generate_bits(const char *psdu, char *data_bits, tx_param &tx); + +#endif /* INCLUDED_IEEE802_11_OFDM_UTILS_H */ diff --git a/lib/wave_llc_impl.cc b/lib/wave_llc_impl.cc new file mode 100644 index 0000000..78635df --- /dev/null +++ b/lib/wave_llc_impl.cc @@ -0,0 +1,79 @@ +/* + * 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 "wave_llc_impl.h" + +#include +#include +#include + +using namespace gr::ieee802_11; + +wave_llc_impl::wave_llc_impl() : + block("wave_llc", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(0, 0, 0)) { + + message_port_register_out(pmt::mp("out")); + + message_port_register_in(pmt::mp("in")); + set_msg_handler(pmt::mp("in"), boost::bind(&wave_llc_impl::make_frame, this, _1)); + + d_header[0] = 0xaa; + d_header[1] = 0xaa; + d_header[2] = 0x03; + d_header[3] = 0x00; + d_header[4] = 0x00; + d_header[5] = 0x00; + d_header[6] = 0x88; + d_header[7] = 0xdc; +} + +void +wave_llc_impl::make_frame (pmt::pmt_t msg) { + + if(pmt::is_eof_object(msg)) { + message_port_pub(pmt::mp("out"), pmt::PMT_EOF); + detail().get()->set_done(true); + return; + } else if(pmt::is_pair(msg)) { + msg = pmt::cdr(msg); + } else if(pmt::is_blob(msg)) { + + } else { + throw std::invalid_argument("wave_llc expects PDU or blob input"); + } + + size_t data_len = pmt::blob_length(msg); + + char *buf = reinterpret_cast(std::malloc( + sizeof(d_header) + data_len)); + + std::memcpy(buf, d_header, sizeof(d_header)); + std::memcpy(buf + sizeof(d_header), pmt::blob_data(msg), data_len); + + pmt::pmt_t llc_msg = pmt::make_blob(buf, sizeof(d_header) + data_len); + message_port_pub(pmt::mp("out"), llc_msg); + + std::free(buf); +} + +wave_llc::sptr +wave_llc::make() { + return gnuradio::get_initial_sptr(new wave_llc_impl()); +} + + diff --git a/lib/wave_llc_impl.h b/lib/wave_llc_impl.h new file mode 100644 index 0000000..8f2233d --- /dev/null +++ b/lib/wave_llc_impl.h @@ -0,0 +1,41 @@ +/* + * 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 . + */ +#ifndef INCLUDED_IEEE802_11_WAVE_LLC_IMPL_H +#define INCLUDED_IEEE802_11_WAVE_LLC_IMPL_H + +#include + +namespace gr { +namespace ieee802_11 { + + class wave_llc_impl : public wave_llc { + + + public: + wave_llc_impl(); + + private: + void make_frame (pmt::pmt_t msg); + + char d_header[8]; + }; + +} // namespace ieee802_11 +} // namespace gr + +#endif /* INCLUDED_IEEE802_11_WAVE_LLC_IMPL_H */ + diff --git a/lib/wave_short_message_impl.cc b/lib/wave_short_message_impl.cc new file mode 100644 index 0000000..c0351a6 --- /dev/null +++ b/lib/wave_short_message_impl.cc @@ -0,0 +1,114 @@ +/* + * 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 "wave_short_message_impl.h" + +#include +#include +#include + +using namespace gr::ieee802_11; + +wave_short_message_impl::wave_short_message_impl(int version) : + block("wave_short_message", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(0, 0, 0)), + d_version(version) { + + message_port_register_out(pmt::mp("out")); + + message_port_register_in(pmt::mp("in")); + set_msg_handler(pmt::mp("in"), boost::bind(&wave_short_message_impl::make_frame, this, _1)); + + + hdr0.version = 0x00; + hdr0.security = 0x00; + hdr0.channel = 0x04; + hdr0.rate = 0x01; + hdr0.power = 0x40; + hdr0.app_class = 0x00; + hdr0.acm_length = 0x00; + + + hdr2.version = 0x02; + hdr2.psid = 0x55; + hdr2.wsm_id = 0x80; +} + +void +wave_short_message_impl::make_frame (pmt::pmt_t msg) { + + if(pmt::is_eof_object(msg)) { + message_port_pub(pmt::mp("out"), pmt::PMT_EOF); + detail().get()->set_done(true); + return; + } else if(pmt::is_symbol(msg)) { + std::string s = pmt::symbol_to_string(msg); + msg = pmt::make_blob(s.data(), s.size()); + } else if(!pmt::is_blob(msg)) { + throw std::invalid_argument("WSM input has to be a blob"); + } + + uint16_t data_len = pmt::blob_length(msg); + + pmt::pmt_t wsm; + char *buf; + + switch(d_version) { + + case 0: + hdr0.length = data_len; + buf = reinterpret_cast(std::malloc(data_len + sizeof(wave_hdr_v0))); + + std::memcpy(buf, &hdr0, sizeof(wave_hdr_v0)); + std::memcpy(buf + sizeof(wave_hdr_v0), pmt::blob_data(msg), data_len); + + wsm = pmt::make_blob(buf, data_len + sizeof(wave_hdr_v0)); + break; + + case 2: + hdr2.length = (data_len << 8) + (data_len >> 8); + buf = reinterpret_cast(std::malloc(data_len + sizeof(wave_hdr_v2))); + + std::memcpy(buf, &hdr2, sizeof(wave_hdr_v2)); + std::memcpy(buf + sizeof(wave_hdr_v2), pmt::blob_data(msg), data_len); + + wsm = pmt::make_blob(buf, data_len + sizeof(wave_hdr_v2)); + break; + + default: + throw std::invalid_argument("wrong version of WSM set"); + break; + } + + std::free(buf); + message_port_pub(pmt::mp("out"), wsm); +} + +void +wave_short_message_impl::set_version(int version) { + if(!(version == 0 || version == 2)) { + throw std::invalid_argument("wrong version of WSM set"); + } + d_version = version; +} + +wave_short_message::sptr +wave_short_message::make(int version) { + return gnuradio::get_initial_sptr(new wave_short_message_impl(version)); +} + + diff --git a/lib/wave_short_message_impl.h b/lib/wave_short_message_impl.h new file mode 100644 index 0000000..decc8e2 --- /dev/null +++ b/lib/wave_short_message_impl.h @@ -0,0 +1,62 @@ +/* + * 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 . + */ +#ifndef INCLUDED_IEEE802_11_WAVE_SHORT_MESSAGE_IMPL_H +#define INCLUDED_IEEE802_11_WAVE_SHORT_MESSAGE_IMPL_H + +#include + +namespace gr { +namespace ieee802_11 { + + struct wave_hdr_v0 { + uint8_t version; + uint8_t security; + uint8_t channel; + uint8_t rate; + uint8_t power; + uint8_t app_class; + uint8_t acm_length; + uint16_t length; + }__attribute__((packed)); + + struct wave_hdr_v2 { + uint8_t version; + uint8_t psid; + uint8_t wsm_id; + uint16_t length; + }__attribute__((packed)); + + class wave_short_message_impl : public wave_short_message { + + + public: + wave_short_message_impl(int version); + + private: + void make_frame (pmt::pmt_t msg); + void set_version(int version); + + wave_hdr_v0 hdr0; + wave_hdr_v2 hdr2; + int d_version; + }; + +} // namespace ieee802_11 +} // namespace gr + +#endif /* INCLUDED_IEEE802_11_WAVE_SHORT_MESSAGE_IMPL_H */ + diff --git a/python/build_utils.py b/python/build_utils.py new file mode 100644 index 0000000..cf58a97 --- /dev/null +++ b/python/build_utils.py @@ -0,0 +1,226 @@ +# +# Copyright 2004,2009,2012 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +"""Misc utilities used at build time +""" + +import re, os, os.path +from build_utils_codes import * + + +# set srcdir to the directory that contains Makefile.am +try: + srcdir = os.environ['srcdir'] +except KeyError, e: + srcdir = "." +srcdir = srcdir + '/' + +# set do_makefile to either true or false dependeing on the environment +try: + if os.environ['do_makefile'] == '0': + do_makefile = False + else: + do_makefile = True +except KeyError, e: + do_makefile = False + +# set do_sources to either true or false dependeing on the environment +try: + if os.environ['do_sources'] == '0': + do_sources = False + else: + do_sources = True +except KeyError, e: + do_sources = True + +name_dict = {} + +def log_output_name (name): + (base, ext) = os.path.splitext (name) + ext = ext[1:] # drop the leading '.' + + entry = name_dict.setdefault (ext, []) + entry.append (name) + +def open_and_log_name (name, dir): + global do_sources + if do_sources: + f = open (name, dir) + else: + f = None + log_output_name (name) + return f + +def expand_template (d, template_filename, extra = ""): + '''Given a dictionary D and a TEMPLATE_FILENAME, expand template into output file + ''' + global do_sources + output_extension = extract_extension (template_filename) + template = open_src (template_filename, 'r') + output_name = d['NAME'] + extra + '.' + output_extension + log_output_name (output_name) + if do_sources: + output = open (output_name, 'w') + do_substitution (d, template, output) + output.close () + template.close () + +def output_glue (dirname): + output_makefile_fragment () + output_ifile_include (dirname) + +def output_makefile_fragment (): + global do_makefile + if not do_makefile: + return +# overwrite the source, which must be writable; this should have been +# checked for beforehand in the top-level Makefile.gen.gen . + f = open (os.path.join (os.environ.get('gendir', os.environ.get('srcdir', '.')), 'Makefile.gen'), 'w') + f.write ('#\n# This file is machine generated. All edits will be overwritten\n#\n') + output_subfrag (f, 'h') + output_subfrag (f, 'i') + output_subfrag (f, 'cc') + f.close () + +def output_ifile_include (dirname): + global do_sources + if do_sources: + f = open ('%s_generated.i' % (dirname,), 'w') + f.write ('//\n// This file is machine generated. All edits will be overwritten\n//\n') + files = name_dict.setdefault ('i', []) + files.sort () + f.write ('%{\n') + for file in files: + f.write ('#include <%s>\n' % (file[0:-1] + 'h',)) + f.write ('%}\n\n') + for file in files: + f.write ('%%include <%s>\n' % (file,)) + +def output_subfrag (f, ext): + files = name_dict.setdefault (ext, []) + files.sort () + f.write ("GENERATED_%s =" % (ext.upper ())) + for file in files: + f.write (" \\\n\t%s" % (file,)) + f.write ("\n\n") + +def extract_extension (template_name): + # template name is something like: GrFIRfilterXXX.h.t + # we return everything between the penultimate . and .t + mo = re.search (r'\.([a-z]+)\.t$', template_name) + if not mo: + raise ValueError, "Incorrectly formed template_name '%s'" % (template_name,) + return mo.group (1) + +def open_src (name, mode): + global srcdir + return open (os.path.join (srcdir, name), mode) + +def do_substitution (d, in_file, out_file): + def repl (match_obj): + key = match_obj.group (1) + # print key + return d[key] + + inp = in_file.read () + out = re.sub (r"@([a-zA-Z0-9_]+)@", repl, inp) + out_file.write (out) + + + +copyright = '''/* -*- c++ -*- */ +/* + * Copyright 2003,2004 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +''' + +def is_complex (code3): + if i_code (code3) == 'c' or o_code (code3) == 'c': + return '1' + else: + return '0' + + +def standard_dict (name, code3, package='gr'): + d = {} + d['NAME'] = name + d['NAME_IMPL'] = name+'_impl' + d['GUARD_NAME'] = 'INCLUDED_%s_%s_H' % (package.upper(), name.upper()) + d['GUARD_NAME_IMPL'] = 'INCLUDED_%s_%s_IMPL_H' % (package.upper(), name.upper()) + d['BASE_NAME'] = re.sub ('^' + package + '_', '', name) + d['SPTR_NAME'] = '%s_sptr' % name + d['WARNING'] = 'WARNING: this file is machine generated. Edits will be overwritten' + d['COPYRIGHT'] = copyright + d['TYPE'] = i_type (code3) + d['I_TYPE'] = i_type (code3) + d['O_TYPE'] = o_type (code3) + d['TAP_TYPE'] = tap_type (code3) + d['IS_COMPLEX'] = is_complex (code3) + return d + + +def standard_dict2 (name, code3, package): + d = {} + d['NAME'] = name + d['BASE_NAME'] = name + d['GUARD_NAME'] = 'INCLUDED_%s_%s_H' % (package.upper(), name.upper()) + d['WARNING'] = 'WARNING: this file is machine generated. Edits will be overwritten' + d['COPYRIGHT'] = copyright + d['TYPE'] = i_type (code3) + d['I_TYPE'] = i_type (code3) + d['O_TYPE'] = o_type (code3) + d['TAP_TYPE'] = tap_type (code3) + d['IS_COMPLEX'] = is_complex (code3) + return d + +def standard_impl_dict2 (name, code3, package): + d = {} + d['NAME'] = name + d['IMPL_NAME'] = name + d['BASE_NAME'] = name.rstrip("impl").rstrip("_") + d['GUARD_NAME'] = 'INCLUDED_%s_%s_H' % (package.upper(), name.upper()) + d['WARNING'] = 'WARNING: this file is machine generated. Edits will be overwritten' + d['COPYRIGHT'] = copyright + d['FIR_TYPE'] = "fir_filter_" + code3 + d['CFIR_TYPE'] = "fir_filter_" + code3[0:2] + 'c' + d['TYPE'] = i_type (code3) + d['I_TYPE'] = i_type (code3) + d['O_TYPE'] = o_type (code3) + d['TAP_TYPE'] = tap_type (code3) + d['IS_COMPLEX'] = is_complex (code3) + return d diff --git a/python/build_utils_codes.py b/python/build_utils_codes.py new file mode 100644 index 0000000..9ea96ba --- /dev/null +++ b/python/build_utils_codes.py @@ -0,0 +1,52 @@ +# +# Copyright 2004 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +def i_code (code3): + return code3[0] + +def o_code (code3): + if len (code3) >= 2: + return code3[1] + else: + return code3[0] + +def tap_code (code3): + if len (code3) >= 3: + return code3[2] + else: + return code3[0] + +def i_type (code3): + return char_to_type[i_code (code3)] + +def o_type (code3): + return char_to_type[o_code (code3)] + +def tap_type (code3): + return char_to_type[tap_code (code3)] + + +char_to_type = {} +char_to_type['s'] = 'short' +char_to_type['i'] = 'int' +char_to_type['f'] = 'float' +char_to_type['c'] = 'gr_complex' +char_to_type['b'] = 'unsigned char' diff --git a/swig/CMakeLists.txt b/swig/CMakeLists.txt index 4751456..01a9487 100644 --- a/swig/CMakeLists.txt +++ b/swig/CMakeLists.txt @@ -26,6 +26,11 @@ endif() include(GrSwig) include(GrPython) +set(GR_SWIG_INCLUDE_DIRS + ${CMAKE_CURRENT_SOURCE_DIR}/../include/ + ${CMAKE_CURRENT_BINARY_DIR}/../include/ +) + ######################################################################## # Setup swig generation ######################################################################## @@ -35,7 +40,12 @@ endforeach(incdir) set(GR_SWIG_LIBRARIES gnuradio-ieee802_11) set(GR_SWIG_DOC_FILE ${CMAKE_CURRENT_BINARY_DIR}/ieee802_11_swig_doc.i) -set(GR_SWIG_DOC_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/../include) +set(GR_SWIG_DOC_DIRS + ${CMAKE_CURRENT_SOURCE_DIR}/../include/ieee802-11/ + ${CMAKE_CURRENT_BINARY_DIR}/../include/ieee802-11/ +) + +set(GR_SWIG_TARGET_DEPS ieee802_11_generated_includes) GR_SWIG_MAKE(ieee802_11_swig ieee802_11_swig.i) @@ -49,7 +59,7 @@ GR_SWIG_INSTALL(TARGETS ieee802_11_swig DESTINATION ${GR_PYTHON_DIR}/ieee802_11) ######################################################################## install( FILES - ieee802_11_swig.i + ieee802_11_swig.i ${CMAKE_CURRENT_BINARY_DIR}/ieee802_11_swig_doc.i DESTINATION ${GR_INCLUDE_DIR}/ieee802_11/swig ) diff --git a/swig/ieee802_11_swig.i b/swig/ieee802_11_swig.i index 420a692..36eaf3d 100644 --- a/swig/ieee802_11_swig.i +++ b/swig/ieee802_11_swig.i @@ -22,27 +22,54 @@ %{ #include "ieee802-11/ether_encap.h" +#include "ieee802-11/moving_average_cc.h" +#include "ieee802-11/moving_average_ff.h" #include "ieee802-11/ofdm_decode_mac.h" #include "ieee802-11/ofdm_decode_signal.h" #include "ieee802-11/ofdm_equalize_symbols.h" +#include "ieee802-11/ofdm_freq_est.h" +#include "ieee802-11/ofdm_mac.h" +#include "ieee802-11/ofdm_mapper.h" #include "ieee802-11/ofdm_parse_mac.h" +#include "ieee802-11/ofdm_pilot.h" +#include "ieee802-11/ofdm_preamble.h" #include "ieee802-11/ofdm_sync_long.h" #include "ieee802-11/ofdm_sync_short.h" +#include "ieee802-11/wave_llc.h" +#include "ieee802-11/wave_short_message.h" %} %include "ieee802-11/ether_encap.h" +%include "ieee802-11/moving_average_cc.h" +%include "ieee802-11/moving_average_ff.h" %include "ieee802-11/ofdm_decode_mac.h" %include "ieee802-11/ofdm_decode_signal.h" %include "ieee802-11/ofdm_equalize_symbols.h" +%include "ieee802-11/ofdm_freq_est.h" +%include "ieee802-11/ofdm_mac.h" +%include "ieee802-11/ofdm_mapper.h" %include "ieee802-11/ofdm_parse_mac.h" +%include "ieee802-11/ofdm_pilot.h" +%include "ieee802-11/ofdm_preamble.h" %include "ieee802-11/ofdm_sync_long.h" %include "ieee802-11/ofdm_sync_short.h" +%include "ieee802-11/wave_llc.h" +%include "ieee802-11/wave_short_message.h" GR_SWIG_BLOCK_MAGIC2(ieee802_11, ether_encap); +GR_SWIG_BLOCK_MAGIC2(ieee802_11, moving_average_cc); +GR_SWIG_BLOCK_MAGIC2(ieee802_11, moving_average_ff); GR_SWIG_BLOCK_MAGIC2(ieee802_11, ofdm_decode_mac); GR_SWIG_BLOCK_MAGIC2(ieee802_11, ofdm_decode_signal); GR_SWIG_BLOCK_MAGIC2(ieee802_11, ofdm_equalize_symbols); +GR_SWIG_BLOCK_MAGIC2(ieee802_11, ofdm_freq_est); +GR_SWIG_BLOCK_MAGIC2(ieee802_11, ofdm_mac); +GR_SWIG_BLOCK_MAGIC2(ieee802_11, ofdm_mapper); GR_SWIG_BLOCK_MAGIC2(ieee802_11, ofdm_parse_mac); +GR_SWIG_BLOCK_MAGIC2(ieee802_11, ofdm_pilot); +GR_SWIG_BLOCK_MAGIC2(ieee802_11, ofdm_preamble); GR_SWIG_BLOCK_MAGIC2(ieee802_11, ofdm_sync_long); GR_SWIG_BLOCK_MAGIC2(ieee802_11, ofdm_sync_short); +GR_SWIG_BLOCK_MAGIC2(ieee802_11, wave_llc); +GR_SWIG_BLOCK_MAGIC2(ieee802_11, wave_short_message);