/* -*- c++ -*- */
/*
 * Copyright 2015,2016 Free Software Foundation, Inc.
 *
 * SPDX-License-Identifier: GPL-3.0-or-later
 *
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "dvbt_bit_inner_deinterleaver_impl.h"
#include <gnuradio/io_signature.h>

#define MAX_MODULATION_ORDER 6
#define INTERLEAVER_BLOCK_SIZE 126

namespace gr {
namespace dtv {

const int dvbt_bit_inner_deinterleaver_impl::d_bsize = INTERLEAVER_BLOCK_SIZE;

dvbt_bit_inner_deinterleaver::sptr
dvbt_bit_inner_deinterleaver::make(int nsize,
                                   dvb_constellation_t constellation,
                                   dvbt_hierarchy_t hierarchy,
                                   dvbt_transmission_mode_t transmission)
{
    return gnuradio::make_block_sptr<dvbt_bit_inner_deinterleaver_impl>(
        nsize, constellation, hierarchy, transmission);
}

/*
 * The private constructor
 */
dvbt_bit_inner_deinterleaver_impl::dvbt_bit_inner_deinterleaver_impl(
    int nsize,
    dvb_constellation_t constellation,
    dvbt_hierarchy_t hierarchy,
    dvbt_transmission_mode_t transmission)
    : block("dvbt_bit_inner_deinterleaver",
            io_signature::make(1, 1, sizeof(unsigned char) * nsize),
            io_signature::make(1, 2, sizeof(unsigned char) * nsize)),
      config(constellation,
             hierarchy,
             gr::dtv::C1_2,
             gr::dtv::C1_2,
             gr::dtv::GI_1_32,
             transmission),
      d_nsize(nsize),
      d_hierarchy(hierarchy)
{
    d_v = config.d_m;
    d_hierarchy = config.d_hierarchy;

    d_perm = (unsigned char*)new (std::nothrow) unsigned char[d_v * d_bsize];
    if (d_perm == NULL) {
        GR_LOG_FATAL(d_logger,
                     "Bit Inner Deinterleaver, cannot allocate memory for d_perm.");
        throw std::bad_alloc();
    }

    // Init permutation table (used for b[e][do])
    for (int i = 0; i < d_bsize * d_v; i++) {
        if (d_hierarchy == NH) {
            d_perm[i] = ((i % d_v) / (d_v / 2)) + 2 * (i % (d_v / 2));
        } else {
            d_perm[i] = (i % (d_v - 2)) / ((d_v - 2) / 2) + 2 * (i % ((d_v - 2) / 2)) + 2;
        }
    }

    if (d_nsize % d_bsize) {
        GR_LOG_ERROR(
            d_logger,
            boost::format(
                "Input size must be multiple of block size: nsize: %1% bsize: %2%") %
                d_nsize % d_bsize);
    }
}

/*
 * Our virtual destructor.
 */
dvbt_bit_inner_deinterleaver_impl::~dvbt_bit_inner_deinterleaver_impl()
{
    delete[] d_perm;
}

void dvbt_bit_inner_deinterleaver_impl::forecast(int noutput_items,
                                                 gr_vector_int& ninput_items_required)
{
    ninput_items_required[0] = noutput_items;
}

int dvbt_bit_inner_deinterleaver_impl::general_work(
    int noutput_items,
    gr_vector_int& ninput_items,
    gr_vector_const_void_star& input_items,
    gr_vector_void_star& output_items)
{
    const unsigned char* in = (const unsigned char*)input_items[0];
    unsigned char* outh = (unsigned char*)output_items[0];
    unsigned char* outl = (unsigned char*)output_items[1];

    int bmax = noutput_items * d_nsize / d_bsize;

    // First index of d_b is Bit interleaver number
    // Second index of d_b is the position inside Bit interleaver
    unsigned char d_b[MAX_MODULATION_ORDER][INTERLEAVER_BLOCK_SIZE];

    for (int bcount = 0; bcount < bmax; bcount++) {
        for (int w = 0; w < d_bsize; w++) {
            int c = in[(bcount * d_bsize) + w];

            for (int e = 0; e < d_v; e++) {
                d_b[e][d_lookup_H[w][e]] = (c >> (d_v - e - 1)) & 1;
            }
        }

        for (int i = 0; i < d_bsize; i++) {
            if (d_hierarchy == NH) {
                // Create output from demultiplexer
                int c = 0;

                for (int k = 0; k < d_v; k++) {
                    c = (c << 1) | d_b[d_perm[(d_v * i) + k]][i];
                }

                outh[(bcount * d_bsize) + i] = c;
            } else {
                int c = 0;

                // High priority output - first 2 streams
                for (int k = 0; k < 2; k++) {
                    c = (c << 1) | d_b[(d_v * i + k) % 2][(d_v * i + k) / 2];
                }

                outh[(bcount * d_bsize) + i] = c;

                c = 0;
                // Low priority output - (v - 2) streams
                for (int k = 2; k < (d_v - 2); k++) {
                    c = (c << 1) | d_b[d_perm[d_v * i + k]][(d_v * i + k) / (d_v - 2)];
                }

                outl[(bcount * d_bsize) + i] = c;
            }
        }
    }

    // Tell runtime system how many input items we consumed on
    // each input stream.
    consume_each(noutput_items);

    // Tell runtime system how many output items we produced.
    return noutput_items;
}

const int dvbt_bit_inner_deinterleaver_impl::d_lookup_H
    [INTERLEAVER_BLOCK_SIZE][MAX_MODULATION_ORDER] = {
        { 0, 63, 105, 42, 21, 84 },   { 1, 64, 106, 43, 22, 85 },
        { 2, 65, 107, 44, 23, 86 },   { 3, 66, 108, 45, 24, 87 },
        { 4, 67, 109, 46, 25, 88 },   { 5, 68, 110, 47, 26, 89 },
        { 6, 69, 111, 48, 27, 90 },   { 7, 70, 112, 49, 28, 91 },
        { 8, 71, 113, 50, 29, 92 },   { 9, 72, 114, 51, 30, 93 },
        { 10, 73, 115, 52, 31, 94 },  { 11, 74, 116, 53, 32, 95 },
        { 12, 75, 117, 54, 33, 96 },  { 13, 76, 118, 55, 34, 97 },
        { 14, 77, 119, 56, 35, 98 },  { 15, 78, 120, 57, 36, 99 },
        { 16, 79, 121, 58, 37, 100 }, { 17, 80, 122, 59, 38, 101 },
        { 18, 81, 123, 60, 39, 102 }, { 19, 82, 124, 61, 40, 103 },
        { 20, 83, 125, 62, 41, 104 }, { 21, 84, 0, 63, 42, 105 },
        { 22, 85, 1, 64, 43, 106 },   { 23, 86, 2, 65, 44, 107 },
        { 24, 87, 3, 66, 45, 108 },   { 25, 88, 4, 67, 46, 109 },
        { 26, 89, 5, 68, 47, 110 },   { 27, 90, 6, 69, 48, 111 },
        { 28, 91, 7, 70, 49, 112 },   { 29, 92, 8, 71, 50, 113 },
        { 30, 93, 9, 72, 51, 114 },   { 31, 94, 10, 73, 52, 115 },
        { 32, 95, 11, 74, 53, 116 },  { 33, 96, 12, 75, 54, 117 },
        { 34, 97, 13, 76, 55, 118 },  { 35, 98, 14, 77, 56, 119 },
        { 36, 99, 15, 78, 57, 120 },  { 37, 100, 16, 79, 58, 121 },
        { 38, 101, 17, 80, 59, 122 }, { 39, 102, 18, 81, 60, 123 },
        { 40, 103, 19, 82, 61, 124 }, { 41, 104, 20, 83, 62, 125 },
        { 42, 105, 21, 84, 63, 0 },   { 43, 106, 22, 85, 64, 1 },
        { 44, 107, 23, 86, 65, 2 },   { 45, 108, 24, 87, 66, 3 },
        { 46, 109, 25, 88, 67, 4 },   { 47, 110, 26, 89, 68, 5 },
        { 48, 111, 27, 90, 69, 6 },   { 49, 112, 28, 91, 70, 7 },
        { 50, 113, 29, 92, 71, 8 },   { 51, 114, 30, 93, 72, 9 },
        { 52, 115, 31, 94, 73, 10 },  { 53, 116, 32, 95, 74, 11 },
        { 54, 117, 33, 96, 75, 12 },  { 55, 118, 34, 97, 76, 13 },
        { 56, 119, 35, 98, 77, 14 },  { 57, 120, 36, 99, 78, 15 },
        { 58, 121, 37, 100, 79, 16 }, { 59, 122, 38, 101, 80, 17 },
        { 60, 123, 39, 102, 81, 18 }, { 61, 124, 40, 103, 82, 19 },
        { 62, 125, 41, 104, 83, 20 }, { 63, 0, 42, 105, 84, 21 },
        { 64, 1, 43, 106, 85, 22 },   { 65, 2, 44, 107, 86, 23 },
        { 66, 3, 45, 108, 87, 24 },   { 67, 4, 46, 109, 88, 25 },
        { 68, 5, 47, 110, 89, 26 },   { 69, 6, 48, 111, 90, 27 },
        { 70, 7, 49, 112, 91, 28 },   { 71, 8, 50, 113, 92, 29 },
        { 72, 9, 51, 114, 93, 30 },   { 73, 10, 52, 115, 94, 31 },
        { 74, 11, 53, 116, 95, 32 },  { 75, 12, 54, 117, 96, 33 },
        { 76, 13, 55, 118, 97, 34 },  { 77, 14, 56, 119, 98, 35 },
        { 78, 15, 57, 120, 99, 36 },  { 79, 16, 58, 121, 100, 37 },
        { 80, 17, 59, 122, 101, 38 }, { 81, 18, 60, 123, 102, 39 },
        { 82, 19, 61, 124, 103, 40 }, { 83, 20, 62, 125, 104, 41 },
        { 84, 21, 63, 0, 105, 42 },   { 85, 22, 64, 1, 106, 43 },
        { 86, 23, 65, 2, 107, 44 },   { 87, 24, 66, 3, 108, 45 },
        { 88, 25, 67, 4, 109, 46 },   { 89, 26, 68, 5, 110, 47 },
        { 90, 27, 69, 6, 111, 48 },   { 91, 28, 70, 7, 112, 49 },
        { 92, 29, 71, 8, 113, 50 },   { 93, 30, 72, 9, 114, 51 },
        { 94, 31, 73, 10, 115, 52 },  { 95, 32, 74, 11, 116, 53 },
        { 96, 33, 75, 12, 117, 54 },  { 97, 34, 76, 13, 118, 55 },
        { 98, 35, 77, 14, 119, 56 },  { 99, 36, 78, 15, 120, 57 },
        { 100, 37, 79, 16, 121, 58 }, { 101, 38, 80, 17, 122, 59 },
        { 102, 39, 81, 18, 123, 60 }, { 103, 40, 82, 19, 124, 61 },
        { 104, 41, 83, 20, 125, 62 }, { 105, 42, 84, 21, 0, 63 },
        { 106, 43, 85, 22, 1, 64 },   { 107, 44, 86, 23, 2, 65 },
        { 108, 45, 87, 24, 3, 66 },   { 109, 46, 88, 25, 4, 67 },
        { 110, 47, 89, 26, 5, 68 },   { 111, 48, 90, 27, 6, 69 },
        { 112, 49, 91, 28, 7, 70 },   { 113, 50, 92, 29, 8, 71 },
        { 114, 51, 93, 30, 9, 72 },   { 115, 52, 94, 31, 10, 73 },
        { 116, 53, 95, 32, 11, 74 },  { 117, 54, 96, 33, 12, 75 },
        { 118, 55, 97, 34, 13, 76 },  { 119, 56, 98, 35, 14, 77 },
        { 120, 57, 99, 36, 15, 78 },  { 121, 58, 100, 37, 16, 79 },
        { 122, 59, 101, 38, 17, 80 }, { 123, 60, 102, 39, 18, 81 },
        { 124, 61, 103, 40, 19, 82 }, { 125, 62, 104, 41, 20, 83 }
    };

} /* namespace dtv */
} /* namespace gr */