/* -*- c++ -*- */
/* Copyright 2012-2016 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.
 */

#ifndef INCLUDED_DIGITAL_HEADER_PAYLOAD_DEMUX_H
#define INCLUDED_DIGITAL_HEADER_PAYLOAD_DEMUX_H

#include <gnuradio/digital/api.h>
#include <gnuradio/block.h>

namespace gr {
  namespace digital {

    /*!
     * \brief Header/Payload demuxer (HPD).
     * \ingroup packet_operators_blk
     *
     * \details
     * This block is designed to demultiplex packets from a bursty transmission.
     * The typical application for this block is the case when you are receiving
     * packets with yet-to-determine length. This block will pass the header
     * section to other blocks for demodulation. Using the information from the
     * demodulated header, it will then output the payload. The beginning of the
     * header needs to be identified by a trigger signal (see below).
     *
     * \section hpd_theory_of_ops Theory of Operation
     *
     * Input 0 takes a continuous transmission of samples (items).
     * Input 1 is an optional input for the trigger signal (mark beginning of
     * packets). In this case, a non-zero value on input 1 identifies the beginning of a packet.
     * Otherwise, a tag with the key specified in \p trigger_tag_key is used as a
     * trigger (its value is irrelevant).
     *
     * Until a trigger signal is detected, all samples are dropped onto the floor.
     * Once a trigger is detected, a total of \p header_len items are copied to output 0.
     * The block then stalls until it receives a message on the message port
     * \p header_data. The message must be a PMT dictionary; all key/value pairs are
     * copied as tags to the first item of the payload (which is assumed to be the
     * first item after the header).
     * The value corresponding to the key specified in \p length_tag_key is read
     * and taken as the payload length. The payload, together with the header data
     * as tags, is then copied to output 1.
     *
     * If the header demodulation fails, the header must send a PMT with value
     * pmt::PMT_F. The state gets reset and the header is ignored.
     *
     * \section hpd_item_sizes Symbols, Items and Item Sizes
     *
     * To generically and transparently handle different kinds of modulations,
     * including OFDM, this block distinguises between \b symbols and \b items.
     *
     * Items are what are consumed at the input. Anything that uses complex samples
     * will therefore use an itemsize of `sizeof(gr_complex)`. Symbols are a way of
     * grouping items. In OFDM, we usually don't care about individual samples, but
     * we do care about full OFDM symbols, so we set \p items_per_symbol to the
     * IFFT / FFT length of the OFDM modulator / demodulator.
     * For single-carrier modulations, this value can be set to the number of
     * samples per symbol, to handle data in number of symbols, or to 1 to
     * handle data in number of samples.
     * If specified, \p guard_interval items are discarded before every symbol.
     * This is useful for demuxing bursts of OFDM signals.
     *
     * On the output, we can deal with symbols directly by setting \p output_symbols
     * to true. In that case, the output item size is the <em>symbol size</em>.
     *
     * \b Example: OFDM with 48 sub-carriers, using a length-64 IFFT on the
     * modulator, and a cyclic-prefix length of 16 samples. In this case,
     * \p itemsize is `sizeof(gr_complex)`, because we're receiving complex
     * samples. One OFDM symbol has 64 samples, hence \p items_per_symbol is
     * set to 64, and \p guard_interval to 16. The header length is specified
     * in number of OFDM symbols. Because we want to deal with full OFDM
     * symbols, we set \p output_symbols to true.
     *
     * \b Example: PSK-modulated signals, with 4 samples per symbol. Again,
     * \p itemsize is `sizeof(gr_complex)` because we're still dealing with
     * complex samples. \p items_per_symbol is 4, because one item is one
     * sample. \p guard_interval must be set to 0. The header length is
     * given in number of PSK symbols.
     *
     * \section hpd_uncertainty Handling timing uncertainty on the trigger
     *
     * By default, the assumption is made that the trigger arrives on *exactly*
     * the sample that the header starts. These triggers typically come from
     * timing synchronization algorithms which may be suboptimal, and have a
     * known timing uncertainty (e.g., we know the trigger might be a sample
     * too early or too late).
     *
     * The demuxer has an option for this case, the \p header_padding. If this
     * value is non-zero, it specifies the number of items that are prepended
     * and appended to the header before copying it to the header output.
     *
     * Example: Say our synchronization algorithm can be off by up to two
     * samples, and the header length is 20 samples. So we set \p header_len
     * to 20, and \p header_padding to 2.
     * Now assume a trigger arrives on sample index 100. We copy a total of
     * 24 samples to the header port, starting at sample index 98.
     *
     * The payload is *not* padded. Let's say the header demod reports a
     * payload length of 100. In the previous examples, we would copy 100
     * samples to the payload port, starting at sample index 120 (this means
     * the padded samples appended to the header are copied to both ports!).
     * However, the header demodulator has the option to specify a payload
     * offset, which cannot exceed the padding value. To do this, include
     * a key `payload_offset` in the message sent back to the HPD. A negative
     * value means the payload starts earlier than otherwise.
     * (If you wanted to always pad the payload, you could set `payload_offset`
     * to `-header_padding` and increase the reported length of the payload).
     *
     * Because the padding is specified in number of items, and not symbols,
     * this value can only be multiples of the number of items per symbol *if*
     * either \p output_symbols is true, or a guard interval is specified (or
     * both). Note that in practice, it is rare that both a guard interval is
     * specified *and* a padding value is required. The difference between the
     * padding value and a guard interval is that a guard interval is part of
     * the signal, and comes with *every* symbol, whereas the header padding
     * is added to only the header, and is not by design.
     *
     * \section hpd_tag_handling Tag Handling
     *
     * Any tags on the input stream are copied to the corresponding output *if* they're
     * on an item that is propagated. Note that a tag on the header items is copied to the
     * header stream; that means the header-parsing block must handle these tags if they
     * should go on the payload.
     * A special case are tags on items that make up the guard interval. These are copied
     * to the first item of the following symbol.
     * If a tag is situated very close to the end of the payload, it might be unclear if
     * it belongs to this packet or the following. In this case, it is possible that the
     * tag might be propagated twice.
     *
     * Tags outside of packets are generally discarded. If there are tags that
     * carry important information that must not be list, there are two
     * additional mechanisms to preserve the tags:
     * - Timing tags might be relevant to know \b when a packet was received. By
     *   specifying the name of a timestamp tag and the sample rate at this block, it
     *   keeps track of the time and will add the time to the first item of every packet.
     *   The name of the timestamp tag is usually 'rx_time' (see, e.g.,
     *   gr::uhd::usrp_source::make()).
     *   The time value must be specified in the UHD time format.
     * - Other tags are simply stored and updated. As an example, the user might want to know the
     *   rx frequency, which UHD stores in the rx_freq tag. In this case, add the tag name 'rx_freq'
     *   to the list of \p special_tags. This block will then always save the most current value of
     *   'rx_freq' and add it to the beginning of every packet.
     *
     */
    class DIGITAL_API header_payload_demux : virtual public block
    {
     public:
      typedef boost::shared_ptr<header_payload_demux> sptr;

      /*!
       * \param header_len Number of symbols per header
       * \param items_per_symbol Number of items per symbol
       * \param guard_interval Number of items between two consecutive symbols
       * \param length_tag_key Key of the frame length tag
       * \param trigger_tag_key Key of the trigger tag
       * \param output_symbols Output symbols (true) or items (false)?
       * \param itemsize Item size (bytes per item)
       * \param timing_tag_key The name of the tag with timing information, usually 'rx_time' or empty (this means timing info is discarded)
       * \param samp_rate Sampling rate at the input. Necessary to calculate the rx time of packets.
       * \param special_tags A vector of strings denoting tags which shall be preserved (see \ref hpd_tag_handling)
       * \param header_padding A number of items that is appended and prepended to the header.
       */
      static sptr make(
          const int header_len,
          const int items_per_symbol=1,
          const int guard_interval=0,
          const std::string &length_tag_key="frame_len",
          const std::string &trigger_tag_key="",
          const bool output_symbols=false,
          const size_t itemsize=sizeof(gr_complex),
          const std::string &timing_tag_key="",
          const double samp_rate=1.0,
          const std::vector<std::string> &special_tags=std::vector<std::string>(),
          const size_t header_padding=0
      );
    };

  } // namespace digital
} // namespace gr

#endif /* INCLUDED_DIGITAL_HEADER_PAYLOAD_DEMUX_H */