From ad590174e02edce789fc9c9cbe14869ed12f98fc Mon Sep 17 00:00:00 2001 From: Manolis Surligas Date: Sun, 1 Sep 2019 12:41:27 +0300 Subject: [PATCH] Implement the generic decoder API To simplify the logic and allow an easy and more efficient way to add new decoders, the new architecture uses only one decoder block. This block takes as input a void* stream and produces PDUs with their metadata. To do so, the block accepts a decoder object. Every decoder should implement the virtual class decoder(). This class provides the necessary API and an arbitrary number of decoders can be supported. The decoding status is reported to the frame_decoder block through the decoder_status_t structure. --- grc/CMakeLists.txt | 1 + grc/satnogs_block_tree.xml | 1 + grc/satnogs_frame_decoder.xml | 63 ++++++++++++++++ include/satnogs/CMakeLists.txt | 2 + include/satnogs/decoder.h | 126 ++++++++++++++++++++++++++++++++ include/satnogs/frame_decoder.h | 60 +++++++++++++++ lib/CMakeLists.txt | 2 + lib/decoder.cc | 78 ++++++++++++++++++++ lib/frame_decoder_impl.cc | 106 +++++++++++++++++++++++++++ lib/frame_decoder_impl.h | 56 ++++++++++++++ swig/satnogs_swig0.i | 9 ++- 11 files changed, 503 insertions(+), 1 deletion(-) create mode 100644 grc/satnogs_frame_decoder.xml create mode 100644 include/satnogs/decoder.h create mode 100644 include/satnogs/frame_decoder.h create mode 100644 lib/decoder.cc create mode 100644 lib/frame_decoder_impl.cc create mode 100644 lib/frame_decoder_impl.h diff --git a/grc/CMakeLists.txt b/grc/CMakeLists.txt index 01034c8..1077b5f 100644 --- a/grc/CMakeLists.txt +++ b/grc/CMakeLists.txt @@ -34,6 +34,7 @@ list(APPEND enabled_blocks satnogs_ccsds_rs_decoder_mm.xml satnogs_decoder_8b10b.xml satnogs_fox_telem_mm.xml + satnogs_frame_decoder.xml satnogs_frame_file_sink.xml satnogs_iq_sink.xml satnogs_lrpt_decoder.xml diff --git a/grc/satnogs_block_tree.xml b/grc/satnogs_block_tree.xml index 0eb2fb2..b9bc906 100644 --- a/grc/satnogs_block_tree.xml +++ b/grc/satnogs_block_tree.xml @@ -43,4 +43,5 @@ satnogs_decoder_8b10b variable_whitening satnogs_frame_acquisition + satnogs_frame_decoder \ No newline at end of file diff --git a/grc/satnogs_frame_decoder.xml b/grc/satnogs_frame_decoder.xml new file mode 100644 index 0000000..1c07c46 --- /dev/null +++ b/grc/satnogs_frame_decoder.xml @@ -0,0 +1,63 @@ + + + Frame Decoder + satnogs_frame_decoder + import satnogs + satnogs.frame_decoder($decoder_object, $itype.size) + + + Input Type + itype + + enum + + + + + + + + + Decoder object + decoder_object + None + raw + + + + in + $itype + + + + reset + message + 1 + + + + out + message + + + \ No newline at end of file diff --git a/include/satnogs/CMakeLists.txt b/include/satnogs/CMakeLists.txt index 7af04b4..e6f543e 100644 --- a/include/satnogs/CMakeLists.txt +++ b/include/satnogs/CMakeLists.txt @@ -42,6 +42,8 @@ list(APPEND HEADER_FILES utils.h udp_msg_source.h tcp_rigctl_msg_source.h + decoder.h + frame_decoder.h frame_encoder.h doppler_correction_cc.h doppler_fit.h diff --git a/include/satnogs/decoder.h b/include/satnogs/decoder.h new file mode 100644 index 0000000..a1e7c37 --- /dev/null +++ b/include/satnogs/decoder.h @@ -0,0 +1,126 @@ +/* -*- c++ -*- */ +/* + * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module + * + * Copyright (C) 2019, 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_DECODER_H +#define INCLUDED_SATNOGS_DECODER_H + +#include +#include +#include +#include + +namespace gr +{ +namespace satnogs +{ + +/** + * The status of the decoder + */ +class decoder_status +{ +public: + bool packed; /**< Indicates if the output is packed bits or unpacked */ + int consumed; /**< The number of input items consumed */ + ssize_t decoded_bits; /**< The number of the decoded bits. */ + pmt::pmt_t metadata; /**< Metadata for the decoded frame */ + + decoder_status () : + packed(false), + consumed(0), + decoded_bits(-1), + metadata(pmt::PMT_NIL) + { + } +}; + +typedef class decoder_status decoder_status_t; + + +/** + * \brief Abstract class that provided the API for the c decoders + * + * This is an abstract class providing the API for the SatNOGS decoders. + * + * The gr-satnogs module tries to provide a unified decoding framework, + * for various satellites. + * Specialization is performed by passing to the generic decoding block the + * appropriate decoder class that implements this abstract class API. + * + */ +class SATNOGS_API decoder +{ +public: + typedef boost::shared_ptr decoder_sptr; + + static int base_unique_id; + + int + unique_id (); + + decoder (int input_item_size, size_t max_frame_len = 8192); + virtual ~decoder (); + + /** + * Decodes a buffer. The difference with the decoder::decode_once() is that + * this method does not reset the internal state of the decoder. + * Therefore, it can be called again and continue the decoding when + * data are available. + * + * @param out the output buffer that will hold the decoded data + * + * @param in the input items + * + * @param len the length of the input buffer in bits + * + * @return the number of decoded bits. Due to the fact that + * some coding schemes may not produce an output that is a multiple of + * 8 bits, it is necessary to count in a per bit basis. If the result + * is not a multiple of 8 bits, the LS bits are padded with zeros. + * If an error occurred an appropriate negative error code is returned + */ + virtual decoder_status_t + decode (uint8_t *out, const void *in, int len) = 0; + + + /** + * Resets the internal state of the decoder to the initial defaults + * + */ + virtual void + reset () = 0; + + size_t + max_frame_len() const; + + int + sizeof_input_item() const; + +private: + const int d_sizeof_in; + const size_t d_max_frame_len; + int d_id; +}; + +} // namespace satnogs +} // namespace gr + +#endif /* INCLUDED_SATNOGS_DECODER_H */ + diff --git a/include/satnogs/frame_decoder.h b/include/satnogs/frame_decoder.h new file mode 100644 index 0000000..7be15d4 --- /dev/null +++ b/include/satnogs/frame_decoder.h @@ -0,0 +1,60 @@ +/* -*- c++ -*- */ +/* + * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module + * + * Copyright (C) 2019, 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_FRAME_DECODER_H +#define INCLUDED_SATNOGS_FRAME_DECODER_H + +#include +#include +#include + +namespace gr { + namespace satnogs { + + /*! + * \brief This is a generic frame decoder block. It takes as input a + * bit stream and produces decoded frames and their metadata. + * + * The decoding is performed by using a proper decoder object. + * Each decoder implements the virtual class ::decoder() + * + * The frame and metadata are produced in a pmt dictionary, with the + * keys "pdu" and "metadata". + * + * \ingroup satnogs + * + */ + class SATNOGS_API frame_decoder : virtual public gr::sync_block + { + public: + typedef boost::shared_ptr sptr; + + /*! + * \brief Return a shared_ptr to a new instance of satnogs::frame_decoder. + * @param decoder_object the decoder object to use + */ + static sptr make(decoder::decoder_sptr decoder_object, int input_size); + }; + + } // namespace satnogs +} // namespace gr + +#endif /* INCLUDED_SATNOGS_FRAME_DECODER_H */ + diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 5be77b1..ac617bc 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -48,7 +48,9 @@ list(APPEND satnogs_sources cw_to_symbol_impl.cc udp_msg_source_impl.cc tcp_rigctl_msg_source_impl.cc + decoder.cc doppler_correction_cc_impl.cc + frame_decoder_impl.cc frame_encoder_impl.cc doppler_fit.cc freq_drift.cc diff --git a/lib/decoder.cc b/lib/decoder.cc new file mode 100644 index 0000000..e3ec362 --- /dev/null +++ b/lib/decoder.cc @@ -0,0 +1,78 @@ +/* -*- c++ -*- */ +/* + * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module + * + * Copyright (C) 2019, 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 + +namespace gr +{ +namespace satnogs +{ + +int decoder::base_unique_id = 1; + +/** + * @note: For internal GNU Radio companion usage. DO NOT EDIT! + * @return the unique id of the decoder object + */ +int +decoder::unique_id () +{ + return d_id; +} + +/** + * Creates a generic decoder object + * @param max_frame_len the maximum allowed frame size in bytes + */ +decoder::decoder(int input_item_size, size_t max_frame_len) + : d_sizeof_in(input_item_size), + d_max_frame_len(max_frame_len), + d_id(base_unique_id++) +{ +} + +decoder::~decoder() +{ +} + +/** + * + * @return the maximum allowed frame length + */ +size_t +decoder::max_frame_len() const +{ + return d_max_frame_len; +} + +int +decoder::sizeof_input_item () const +{ + return d_sizeof_in; +} + +} /* namespace satnogs */ +} /* namespace gr */ + diff --git a/lib/frame_decoder_impl.cc b/lib/frame_decoder_impl.cc new file mode 100644 index 0000000..848315d --- /dev/null +++ b/lib/frame_decoder_impl.cc @@ -0,0 +1,106 @@ +/* -*- c++ -*- */ +/* + * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module + * + * Copyright (C) 2019, 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 "frame_decoder_impl.h" + +namespace gr +{ +namespace satnogs +{ + +frame_decoder::sptr +frame_decoder::make (decoder::decoder_sptr decoder_object, int input_size) +{ + return gnuradio::get_initial_sptr (new frame_decoder_impl (decoder_object, + input_size)); +} + +/* + * The private constructor + */ +frame_decoder_impl::frame_decoder_impl (decoder::decoder_sptr decoder_object, + int input_size) : + gr::sync_block ("frame_decoder", + gr::io_signature::make (1, 1, input_size), + gr::io_signature::make (0, 0, 0)), + d_decoder (decoder_object) +{ + if (input_size != decoder_object->sizeof_input_item ()) { + throw std::invalid_argument ( + "Size mismatch between the block input and the decoder"); + } + + message_port_register_in (pmt::mp ("reset")); + message_port_register_out (pmt::mp ("out")); + + d_frame = new uint8_t[decoder_object->max_frame_len () * 8]; + + set_msg_handler (pmt::mp ("reset"), + boost::bind (&frame_decoder_impl::reset, this, _1)); +} + +/* + * Our virtual destructor. + */ +frame_decoder_impl::~frame_decoder_impl () +{ +} + +void +frame_decoder_impl::reset (pmt::pmt_t m) +{ + d_decoder->reset(); +} + +int +frame_decoder_impl::work (int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + const void *in = input_items[0]; + pmt::pmt_t res = pmt::make_dict(); + + decoder_status_t status = d_decoder->decode (d_frame, in, noutput_items); + if (status.decoded_bits > 0) { + if (status.packed) { + res = pmt::dict_add(res, pmt::mp("pdu"), + pmt::make_blob (d_frame, (size_t)status.decoded_bits / 8)); + } + else { + res = pmt::dict_add ( + res, pmt::mp ("pdu"), + pmt::make_blob (d_frame, (size_t) status.decoded_bits)); + } + res = pmt::dict_add (res, pmt::mp ("metadata"), status.metadata); + message_port_pub (pmt::mp ("out"), res); + } + + // Tell runtime system how many output items we produced. + return status.consumed; +} + +} /* namespace satnogs */ +} /* namespace gr */ + diff --git a/lib/frame_decoder_impl.h b/lib/frame_decoder_impl.h new file mode 100644 index 0000000..fe04937 --- /dev/null +++ b/lib/frame_decoder_impl.h @@ -0,0 +1,56 @@ +/* -*- c++ -*- */ +/* + * gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module + * + * Copyright (C) 2019, 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_FRAME_DECODER_IMPL_H +#define INCLUDED_SATNOGS_FRAME_DECODER_IMPL_H + +#include + +namespace gr +{ +namespace satnogs +{ + +class frame_decoder_impl : public frame_decoder +{ + +public: + frame_decoder_impl (decoder::decoder_sptr decoder_object, int input_size); + ~frame_decoder_impl (); + + // Where all the action really happens + int + work (int noutput_items, gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + +private: + decoder::decoder_sptr d_decoder; + uint8_t *d_frame; + + void + reset(pmt::pmt_t m); +}; + +} // namespace satnogs +} // namespace gr + +#endif /* INCLUDED_SATNOGS_FRAME_DECODER_IMPL_H */ + diff --git a/swig/satnogs_swig0.i b/swig/satnogs_swig0.i index 40d4064..eb031c9 100644 --- a/swig/satnogs_swig0.i +++ b/swig/satnogs_swig0.i @@ -10,7 +10,8 @@ %template(whitening_sptr) boost::shared_ptr; - +%nodefaultctor gr::satnogs::decoder; +%template(decoder_sptr) boost::shared_ptr; %{ #include "satnogs/morse_tree.h" @@ -19,7 +20,9 @@ #include "satnogs/cw_to_symbol.h" #include "satnogs/udp_msg_source.h" #include "satnogs/tcp_rigctl_msg_source.h" +#include "satnogs/decoder.h" #include "satnogs/doppler_correction_cc.h" +#include "satnogs/frame_decoder.h" #include "satnogs/frame_encoder.h" #include "satnogs/upsat_fsk_frame_acquisition.h" #include "satnogs/upsat_fsk_frame_encoder.h" @@ -46,6 +49,7 @@ %include "satnogs/morse_tree.h" +%include "satnogs/decoder.h" %include "satnogs/morse_decoder.h" GR_SWIG_BLOCK_MAGIC2(satnogs, morse_decoder); @@ -62,6 +66,9 @@ GR_SWIG_BLOCK_MAGIC2(satnogs, udp_msg_source); %include "satnogs/tcp_rigctl_msg_source.h" GR_SWIG_BLOCK_MAGIC2(satnogs, tcp_rigctl_msg_source); +%include "satnogs/frame_decoder.h" +GR_SWIG_BLOCK_MAGIC2(satnogs, frame_decoder); + %include "satnogs/frame_encoder.h" GR_SWIG_BLOCK_MAGIC2(satnogs, frame_encoder);