From 02801c9a3f0568a4c5ab4dabd020fb44a24b696b Mon Sep 17 00:00:00 2001 From: Manolis Surligas Date: Tue, 30 Jan 2018 01:44:16 +0200 Subject: [PATCH] Improve 8b10b decoder performance and add the CCSDS RS decoder --- CMakeLists.txt | 1 + cmake/Modules/FindFec.cmake | 25 +++++ grc/CMakeLists.txt | 3 +- grc/satnogs_block_tree.xml | 2 + grc/satnogs_ccsds_rs_decoder_mm.xml | 17 ++++ grc/satnogs_decoder_8b10b.xml | 52 +++++------ include/satnogs/CMakeLists.txt | 3 +- include/satnogs/ccsds_rs_decoder_mm.h | 56 ++++++++++++ lib/CMakeLists.txt | 5 +- lib/ccsds_rs_decoder_mm_impl.cc | 97 ++++++++++++++++++++ lib/ccsds_rs_decoder_mm_impl.h | 47 ++++++++++ lib/decoder_8b10b_impl.cc | 126 ++++++++++++++------------ lib/decoder_8b10b_impl.h | 13 ++- swig/satnogs_swig0.i | 6 ++ 14 files changed, 360 insertions(+), 93 deletions(-) create mode 100644 cmake/Modules/FindFec.cmake create mode 100644 grc/satnogs_ccsds_rs_decoder_mm.xml create mode 100644 include/satnogs/ccsds_rs_decoder_mm.h create mode 100644 lib/ccsds_rs_decoder_mm_impl.cc create mode 100644 lib/ccsds_rs_decoder_mm_impl.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d05085e..4be403f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -131,6 +131,7 @@ find_package(Volk REQUIRED) find_package(OggVorbis REQUIRED) find_package(PNG REQUIRED) find_package(png++ REQUIRED) +find_package(Fec REQUIRED) ######################################################################## # Include or not into the module blocks for debugging diff --git a/cmake/Modules/FindFec.cmake b/cmake/Modules/FindFec.cmake new file mode 100644 index 0000000..d1197a8 --- /dev/null +++ b/cmake/Modules/FindFec.cmake @@ -0,0 +1,25 @@ +INCLUDE(FindPkgConfig) +PKG_CHECK_MODULES(PC_FEC fec) + +FIND_PATH( + FEC_INCLUDE_DIRS + NAMES fec.h + HINTS $ENV{FEC_DIR}/include + ${PC_FEC_INCLUDEDIR} + PATHS /usr/local/include + /usr/include +) + +FIND_LIBRARY( + FEC_LIBRARIES + NAMES fec + HINTS $ENV{FEC_DIR}/lib + ${PC_FEC_LIBDIR} + PATHS /usr/local/lib + /usr/local/lib64 + /usr/lib + /usr/lib64 +) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(FEC DEFAULT_MSG FEC_LIBRARIES FEC_INCLUDE_DIRS) \ No newline at end of file diff --git a/grc/CMakeLists.txt b/grc/CMakeLists.txt index 1991aa8..81549ec 100644 --- a/grc/CMakeLists.txt +++ b/grc/CMakeLists.txt @@ -53,5 +53,6 @@ endif() install(FILES ${enabled_blocks} satnogs_quad_demod_filter_ff.xml - satnogs_decoder_8b10b.xml DESTINATION share/gnuradio/grc/blocks + satnogs_decoder_8b10b.xml + satnogs_ccsds_rs_decoder_mm.xml DESTINATION share/gnuradio/grc/blocks ) diff --git a/grc/satnogs_block_tree.xml b/grc/satnogs_block_tree.xml index 17f5742..d80bfc0 100644 --- a/grc/satnogs_block_tree.xml +++ b/grc/satnogs_block_tree.xml @@ -30,4 +30,6 @@ satnogs_ax25_decoder_bm satnogs_waterfall_sink satnogs_quad_demod_filter_ff + satnogs_ccsds_rs_decoder_mm + satnogs_decoder_8b10b \ No newline at end of file diff --git a/grc/satnogs_ccsds_rs_decoder_mm.xml b/grc/satnogs_ccsds_rs_decoder_mm.xml new file mode 100644 index 0000000..6b1a6c2 --- /dev/null +++ b/grc/satnogs_ccsds_rs_decoder_mm.xml @@ -0,0 +1,17 @@ + + + CCSDS (255,223) RS Decoder + satnogs_ccsds_rs_decoder_mm + import satnogs + satnogs.ccsds_rs_decoder_mm() + + + in + message + + + + pdu + message + + diff --git a/grc/satnogs_decoder_8b10b.xml b/grc/satnogs_decoder_8b10b.xml index 03c9b95..70c593c 100644 --- a/grc/satnogs_decoder_8b10b.xml +++ b/grc/satnogs_decoder_8b10b.xml @@ -1,35 +1,33 @@ - 8b10b Decoder - satnogs_decoder_8b10b - [SatNOGS] - import satnogs - satnogs.decoder_8b10b($control_symbol, $max_frame_len - ) - + 8b10b Decoder + satnogs_decoder_8b10b + import satnogs + satnogs.decoder_8b10b($control_symbol, $max_frame_len) + - - Control symbols - control_symbol - 0011111010 - string - + + Control symbols + control_symbol + 0011111010 + string + - - Maximum frame length - max_frame_len - 960 - int - + + Maximum frame length + max_frame_len + 960 + int + - - in - byte - + + in + byte + - - pdu - message - + + pdu + message + diff --git a/include/satnogs/CMakeLists.txt b/include/satnogs/CMakeLists.txt index d66a61a..b2c22de 100644 --- a/include/satnogs/CMakeLists.txt +++ b/include/satnogs/CMakeLists.txt @@ -68,5 +68,6 @@ endif() install(FILES ${HEADER_FILES} quad_demod_filter_ff.h - decoder_8b10b.h DESTINATION include/satnogs + decoder_8b10b.h + ccsds_rs_decoder_mm.h DESTINATION include/satnogs ) \ No newline at end of file diff --git a/include/satnogs/ccsds_rs_decoder_mm.h b/include/satnogs/ccsds_rs_decoder_mm.h new file mode 100644 index 0000000..1efafd4 --- /dev/null +++ b/include/satnogs/ccsds_rs_decoder_mm.h @@ -0,0 +1,56 @@ +/* -*- c++ -*- */ +/* + * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module + * + * Copyright (C) 2018, Libre Space Foundation + * + * 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_SATNOGS_CCSDS_RS_DECODER_MM_H +#define INCLUDED_SATNOGS_CCSDS_RS_DECODER_MM_H + +#include +#include + +namespace gr { + namespace satnogs { + + /*! + * \brief <+description of block+> + * \ingroup satnogs + * + */ + class SATNOGS_API ccsds_rs_decoder_mm : virtual public gr::block + { + public: + typedef boost::shared_ptr sptr; + + /*! + * \brief Return a shared_ptr to a new instance of satnogs::ccsds_rs_decoder_mm. + * + * To avoid accidental use of raw pointers, satnogs::ccsds_rs_decoder_mm's + * constructor is in a private implementation + * class. satnogs::ccsds_rs_decoder_mm::make is the public interface for + * creating new instances. + */ + static sptr make(); + }; + + } // namespace satnogs +} // namespace gr + +#endif /* INCLUDED_SATNOGS_CCSDS_RS_DECODER_MM_H */ + diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 99857af..8bf9a01 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -29,6 +29,7 @@ include_directories( ${OGG_INCLUDE_DIR} ${PNG_INCLUDE_DIR} ${png++_INCLUDE_DIRS} + ${FEC_INCLUDE_DIRS} ) link_directories(${Boost_LIBRARY_DIRS}) @@ -66,7 +67,8 @@ list(APPEND satnogs_sources frame_file_sink_impl.cc iq_sink_impl.cc quad_demod_filter_ff_impl.cc - decoder_8b10b_impl.cc) + decoder_8b10b_impl.cc + ccsds_rs_decoder_mm_impl.cc) if(${INCLUDE_DEBUG_BLOCKS}) list(APPEND satnogs_sources ${satnogs_debug_sources}) @@ -88,6 +90,7 @@ target_link_libraries(gnuradio-satnogs ${OGGVORBIS_LIBRARIES} ${PNG_LIBRARIES} ${png++_LIBRARIES} + ${FEC_LIBRARIES} ) set_target_properties(gnuradio-satnogs PROPERTIES DEFINE_SYMBOL "gnuradio_satnogs_EXPORTS") diff --git a/lib/ccsds_rs_decoder_mm_impl.cc b/lib/ccsds_rs_decoder_mm_impl.cc new file mode 100644 index 0000000..1f94b09 --- /dev/null +++ b/lib/ccsds_rs_decoder_mm_impl.cc @@ -0,0 +1,97 @@ +/* -*- c++ -*- */ +/* + * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module + * + * Copyright (C) 2018, Libre Space Foundation + * + * 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 . + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "ccsds_rs_decoder_mm_impl.h" + +#include +extern "C" { + #include +} + +namespace gr { + namespace satnogs { + + ccsds_rs_decoder_mm::sptr + ccsds_rs_decoder_mm::make() + { + return gnuradio::get_initial_sptr + (new ccsds_rs_decoder_mm_impl()); + } + + /* + * The private constructor + */ + ccsds_rs_decoder_mm_impl::ccsds_rs_decoder_mm_impl() + : gr::block("ccsds_rs_decoder_mm", + gr::io_signature::make(0, 0, 0), + gr::io_signature::make(0, 0, 0)) + { + message_port_register_in(pmt::mp("in")); + message_port_register_out(pmt::mp("pdu")); + + set_msg_handler ( + pmt::mp ("in"), + boost::bind (&ccsds_rs_decoder_mm_impl::message_handler, this, _1)); + } + + void + ccsds_rs_decoder_mm_impl::message_handler (pmt::pmt_t m) + { + uint8_t data[255]; + int erasures[255]; + const uint8_t *data_ref; + size_t data_len; + const int *erasures_ref; + size_t erasures_len; + + pmt::pmt_t pmt_data = pmt::dict_ref(m, pmt::mp("pdu"), pmt::PMT_NIL); + pmt::pmt_t pmt_erasures = pmt::dict_ref(m, pmt::mp("erasures"), + pmt::PMT_NIL); + if (pmt::equal (pmt::PMT_NIL, pmt_data) + || pmt::equal (pmt::PMT_NIL, pmt_erasures)) { + LOG_ERROR("Invalid message format."); + } + + data_ref = pmt::u8vector_elements(pmt_data, data_len); + memcpy(data, data_ref, data_len); + + erasures_len = pmt::blob_length(pmt_erasures); + erasures_ref = pmt::s32vector_elements(pmt_erasures, erasures_len); + memcpy(erasures, erasures_ref, erasures_len * sizeof(int)); + + decode_rs_ccsds(data, erasures, (int)erasures_len, (int)(255 - data_len)); + message_port_pub(pmt::mp("pdu"), pmt::make_blob(data, 223)); + } + + /* + * Our virtual destructor. + */ + ccsds_rs_decoder_mm_impl::~ccsds_rs_decoder_mm_impl() + { + } + + } /* namespace satnogs */ +} /* namespace gr */ + diff --git a/lib/ccsds_rs_decoder_mm_impl.h b/lib/ccsds_rs_decoder_mm_impl.h new file mode 100644 index 0000000..0524218 --- /dev/null +++ b/lib/ccsds_rs_decoder_mm_impl.h @@ -0,0 +1,47 @@ +/* -*- c++ -*- */ +/* + * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module + * + * Copyright (C) 2018, Libre Space Foundation + * + * 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_SATNOGS_CCSDS_RS_DECODER_MM_IMPL_H +#define INCLUDED_SATNOGS_CCSDS_RS_DECODER_MM_IMPL_H + +#include + +namespace gr +{ + namespace satnogs + { + + class ccsds_rs_decoder_mm_impl : public ccsds_rs_decoder_mm + { + private: + + void + message_handler(pmt::pmt_t m); + + public: + ccsds_rs_decoder_mm_impl (); + ~ccsds_rs_decoder_mm_impl (); + }; + + } // namespace satnogs +} // namespace gr + +#endif /* INCLUDED_SATNOGS_CCSDS_RS_DECODER_MM_IMPL_H */ + diff --git a/lib/decoder_8b10b_impl.cc b/lib/decoder_8b10b_impl.cc index d555bd7..dcaa8b6 100644 --- a/lib/decoder_8b10b_impl.cc +++ b/lib/decoder_8b10b_impl.cc @@ -24,6 +24,8 @@ #include #include "decoder_8b10b_impl.h" +#include + #include namespace gr @@ -48,6 +50,7 @@ namespace gr gr::io_signature::make (1, 1, sizeof(char)), gr::io_signature::make (0, 0, 0)), d_max_frame_len (max_frame_len), + d_erasure_cnt (0), d_control_symbol_pos (0), d_control_symbol_neg (0), d_data_reg (0), @@ -55,19 +58,19 @@ namespace gr d_wrong_bits_neg (0), d_nwrong (0), d_nwrong_neg (0), - d_10b_cnt (1), d_word (0), + d_word_cnt (0), d_state (IN_SYNC) { message_port_register_out (pmt::mp ("pdu")); + set_output_multiple(10); if (!set_access_code (control_symbol)) { - GR_LOG_ERROR(d_logger, "control_symbol is not 10 bits"); throw std::out_of_range ("control_symbol is not 10 bits"); } - d_8b_words = (uint8_t*) malloc (d_max_frame_len / 10); - d_erasures = (uint8_t*) malloc (d_max_frame_len / 10); + d_8b_words = new uint8_t [d_max_frame_len / 10]; + d_erasures_indexes = new int [d_max_frame_len / 10]; } /* @@ -75,6 +78,8 @@ namespace gr */ decoder_8b10b_impl::~decoder_8b10b_impl () { + delete [] d_8b_words; + delete [] d_erasures_indexes; } bool @@ -128,8 +133,22 @@ namespace gr } /* report that there is erasure to this 10 bits */ - d_8b_words[write_pos - 1] = min_pos; - d_erasures[write_pos - 1] = (min_dist != 0); + d_8b_words[write_pos] = min_pos; + + /* If we did not found a perfect match, mark this index as erasure */ + if(min_dist != 0) { + d_erasures_indexes[d_erasure_cnt++] = write_pos; + } + } + + static inline uint16_t + pack_10b_word(const uint8_t *in) + { + return ((in[0] & 0x1) << 9) | ((in[1] & 0x1) << 8) + | ((in[2] & 0x1) << 7) | ((in[3] & 0x1) << 6) + | ((in[4] & 0x1) << 5) | ((in[5] & 0x1) << 4) + | ((in[6] & 0x1) << 3) | ((in[7] & 0x1) << 2) + | ((in[8] & 0x1) << 1) | (in[9] & 0x1); } int @@ -137,64 +156,55 @@ namespace gr gr_vector_const_void_star &input_items, gr_vector_void_star &output_items) { + int i; const uint8_t *in = (const uint8_t *) input_items[0]; - for (int i = 0; i < noutput_items; i++) { + /* Search for the Comma symbol */ + if(d_state == IN_SYNC) { + for (i = 0; i < noutput_items; i++) { + d_data_reg = (d_data_reg << 1) | (in[i] & 0x1); + d_wrong_bits = (d_data_reg ^ d_control_symbol_pos) & 0x3FF; + d_wrong_bits_neg = (d_data_reg ^ d_control_symbol_neg) & 0x3FF; + d_nwrong = gr::blocks::count_bits16 (d_wrong_bits); + d_nwrong_neg = gr::blocks::count_bits16 (d_wrong_bits_neg); - d_data_reg = (d_data_reg << 1) | (in[i] & 0x1); - - switch (d_state) - { - case IN_SYNC: - - d_wrong_bits = (d_data_reg ^ d_control_symbol_pos) & 0x3FF; - d_wrong_bits_neg = (d_data_reg ^ d_control_symbol_neg) & 0x3FF; - d_nwrong = gr::blocks::count_bits16 (d_wrong_bits); - d_nwrong_neg = gr::blocks::count_bits16 (d_wrong_bits_neg); - - /* we found the controls symbol */ - if ((d_nwrong == 0) || (d_nwrong_neg == 0)) { - d_state = DECODING; - } - - break; - - case DECODING: - - if (d_10b_cnt <= d_max_frame_len) { - if ((d_10b_cnt % 10 == 0) && (d_10b_cnt < d_max_frame_len)) { - - d_word = (d_data_reg & 0x3FF); - - /* Revert 10b to 8b and accumulate! */ - process_10b (d_10b_cnt / 10); - } - - if (d_10b_cnt == d_max_frame_len) { - d_state = IN_SYNC; - d_10b_cnt = 0; // one is added after the if - d_word = 0; // zero it after you use it to prepare for next round - - pmt::pmt_t data = pmt::init_u8vector (d_max_frame_len / 10, - d_8b_words); - pmt::pmt_t erasures = pmt::init_u8vector (d_max_frame_len / 10, - d_erasures); - - pmt::pmt_t out = pmt::cons (data, erasures); - message_port_pub (pmt::mp ("pdu"), out); - } - - d_10b_cnt++; - } - - break; - - default: - GR_LOG_ERROR(d_logger, "Invalid state"); + /* we found the controls symbol */ + if ((d_nwrong == 0) || (d_nwrong_neg == 0)) { + d_erasure_cnt = 0; + d_word_cnt = 0; + d_state = DECODING; + return i + 1; } + } + return noutput_items; } - // Tell runtime system how many output items we produced. + /* + * From now one, we have a SYNC so we process the data + * in chunks of 10 bits + */ + for(i = 0; i < noutput_items / 10; i++) { + d_word = pack_10b_word(&in[i * 10]); + + /* Revert 10b to 8b and accumulate! */ + process_10b (d_word_cnt); + d_word_cnt++; + + + if(d_word_cnt == d_max_frame_len) { + d_state = IN_SYNC; + pmt::pmt_t data = pmt::init_u8vector (d_max_frame_len / 10, + d_8b_words); + pmt::pmt_t erasures = pmt::init_s32vector (d_erasure_cnt, + d_erasures_indexes); + pmt::pmt_t out = pmt::make_dict(); + pmt::dict_add(out, pmt::mp("pdu"), data); + pmt::dict_add(out, pmt::mp("erasures"), erasures); + + message_port_pub (pmt::mp ("pdu"), out); + return (i+1) * 10; + } + } return noutput_items; } diff --git a/lib/decoder_8b10b_impl.h b/lib/decoder_8b10b_impl.h index 4bcf91a..a389042 100644 --- a/lib/decoder_8b10b_impl.h +++ b/lib/decoder_8b10b_impl.h @@ -31,17 +31,20 @@ namespace gr class decoder_8b10b_impl : public decoder_8b10b { private: - size_t d_max_frame_len; + const size_t d_max_frame_len; + size_t d_erasure_cnt; uint16_t d_control_symbol_pos; uint16_t d_control_symbol_neg; uint16_t d_data_reg; - uint16_t d_wrong_bits, d_wrong_bits_neg; - uint8_t d_nwrong, d_nwrong_neg; - uint16_t d_10b_cnt; + uint16_t d_wrong_bits; + uint16_t d_wrong_bits_neg; + uint8_t d_nwrong; + uint8_t d_nwrong_neg; uint16_t d_word; + size_t d_word_cnt; uint8_t *d_8b_words; - uint8_t *d_erasures; + int *d_erasures_indexes; int d_lookup_8b10b[2][256] = { diff --git a/swig/satnogs_swig0.i b/swig/satnogs_swig0.i index 04654af..a374178 100644 --- a/swig/satnogs_swig0.i +++ b/swig/satnogs_swig0.i @@ -33,6 +33,7 @@ #include "satnogs/iq_sink.h" #include "satnogs/quad_demod_filter_ff.h" #include "satnogs/decoder_8b10b.h" +#include "satnogs/ccsds_rs_decoder_mm.h" %} @@ -99,7 +100,12 @@ GR_SWIG_BLOCK_MAGIC2(satnogs, frame_file_sink); %include "satnogs/iq_sink.h" GR_SWIG_BLOCK_MAGIC2(satnogs, iq_sink); + %include "satnogs/quad_demod_filter_ff.h" GR_SWIG_BLOCK_MAGIC2(satnogs, quad_demod_filter_ff); + %include "satnogs/decoder_8b10b.h" GR_SWIG_BLOCK_MAGIC2(satnogs, decoder_8b10b); + +%include "satnogs/ccsds_rs_decoder_mm.h" +GR_SWIG_BLOCK_MAGIC2(satnogs, ccsds_rs_decoder_mm);