/* -*- c++ -*- */
/* Copyright 2012-2016 Free Software Foundation, Inc.
 *
 * This file is part of GNU Radio
 *
 * SPDX-License-Identifier: GPL-3.0-or-later
 *
 */

#ifndef INCLUDED_DIGITAL_HEADER_PAYLOAD_DEMUX_H
#define INCLUDED_DIGITAL_HEADER_PAYLOAD_DEMUX_H

#include <gnuradio/block.h>
#include <gnuradio/digital/api.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 distinguishes 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 std::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 */
