File: decode_rs_impl.cc

package info (click to toggle)
gr-satellites 5.8.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 10,836 kB
  • sloc: python: 29,546; cpp: 5,448; ansic: 1,247; sh: 118; makefile: 24
file content (175 lines) | stat: -rw-r--r-- 4,968 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/* -*- c++ -*- */
/*
 * Copyright 2016,2020 Daniel Estevez <daniel@destevez.net>
 *
 * This file is part of gr-satellites
 *
 * SPDX-License-Identifier: GPL-3.0-or-later
 *
 */

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

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

#include <algorithm>
#include <exception>

extern "C" {
#include "libfec/fec.h"
}

namespace gr {
namespace satellites {

decode_rs::sptr decode_rs::make(int dual_basis, int interleave)
{
    return gnuradio::make_block_sptr<decode_rs_impl>(dual_basis, interleave);
}

decode_rs::sptr
decode_rs::make(int symsize, int gfpoly, int fcr, int prim, int nroots, int interleave)
{
    return gnuradio::make_block_sptr<decode_rs_impl>(
        symsize, gfpoly, fcr, prim, nroots, interleave);
}

/*
 * The private constructor
 */
decode_rs_impl::decode_rs_impl(bool dual_basis, int interleave)
    : gr::block(
          "decode_rs", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)),
      d_interleave(interleave)
{
    if (dual_basis) {
        d_decode_rs = [](uint8_t* data) { return decode_rs_ccsds(data, NULL, 0, 0); };
    } else {
        d_decode_rs = [](uint8_t* data) { return decode_rs_8(data, NULL, 0, 0); };
    }
    d_rs_codeword.resize(d_ccsds_nn);
    d_nroots = d_ccsds_nroots;

    check_interleave();
    set_message_ports();
}

/*
 * The private constructor
 */
decode_rs_impl::decode_rs_impl(
    int symsize, int gfpoly, int fcr, int prim, int nroots, int interleave)
    : gr::block(
          "decode_rs", gr::io_signature::make(0, 0, 0), gr::io_signature::make(0, 0, 0)),
      d_interleave(interleave)
{
    d_rs_p = init_rs_char(symsize, gfpoly, fcr, prim, nroots, 0);
    if (!d_rs_p) {
        throw std::runtime_error("Unable to initialize Reed-Solomon definition");
    }
    d_decode_rs = [this](uint8_t* data) { return decode_rs_char(d_rs_p, data, 0, 0); };

    d_rs_codeword.resize((1U << symsize) - 1);
    d_nroots = nroots;

    check_interleave();
    set_message_ports();
}

void decode_rs_impl::check_interleave()
{
    if (d_interleave <= 0) {
        throw std::runtime_error("Invalid interleave value = " +
                                 std::to_string(d_interleave));
    }
}

void decode_rs_impl::set_message_ports()
{
    message_port_register_out(pmt::mp("out"));
    message_port_register_in(pmt::mp("in"));
    set_msg_handler(pmt::mp("in"), [this](pmt::pmt_t msg) { this->msg_handler(msg); });
}

/*
 * Our virtual destructor.
 */
decode_rs_impl::~decode_rs_impl()
{
    if (d_rs_p) {
        free_rs_char(d_rs_p);
    }
}

void decode_rs_impl::forecast(int noutput_items, gr_vector_int& ninput_items_required) {}

int decode_rs_impl::general_work(int noutput_items,
                                 gr_vector_int& ninput_items,
                                 gr_vector_const_void_star& input_items,
                                 gr_vector_void_star& output_items)
{
    return 0;
}

void decode_rs_impl::msg_handler(pmt::pmt_t pmt_msg)
{
    auto msg = pmt::u8vector_elements(pmt::cdr(pmt_msg));
    int errors = 0;

    if (msg.size() % d_interleave != 0) {
        d_logger->warn("Reed-Solomon message size not divisible by interleave "
                       "depth. size = {:d}, interleave = {:d}",
                       msg.size(),
                       d_interleave);
        return;
    }

    int rs_nn = msg.size() / d_interleave;
    if (rs_nn <= d_nroots || (unsigned)rs_nn > d_rs_codeword.size()) {
        d_logger->error("Wrong Reed-Solomon message size. size = {:d}, interleave "
                        "= {:d}, RS code ({:d}, {:d})",
                        msg.size(),
                        d_interleave,
                        d_rs_codeword.size(),
                        d_rs_codeword.size() - d_nroots);
        return;
    }

    d_output_frame.resize(msg.size() - d_interleave * d_nroots);
    const auto pad = d_rs_codeword.size() - rs_nn;

    for (int j = 0; j < d_interleave; ++j) {
        std::fill(d_rs_codeword.begin(), d_rs_codeword.begin() + pad, 0);
        for (int k = 0; k < rs_nn; ++k) {
            d_rs_codeword[pad + k] = msg[j + k * d_interleave];
        }

        auto rs_res = d_decode_rs(d_rs_codeword.data());
        if (rs_res < 0) {
            d_logger->debug("Reed-Solomon decode fail (interleaver path {:d})", j);
            return;
        }
        d_logger->debug(
            "Reed-Solomon decode corrected {:d} bytes (interleaver path {:d})",
            rs_res,
            j);
        errors += rs_res;

        for (int k = 0; k < rs_nn - d_nroots; ++k) {
            d_output_frame[j + k * d_interleave] = d_rs_codeword[pad + k];
        }
    }

    auto meta =
        pmt::dict_add(pmt::car(pmt_msg), pmt::mp("rs_errors"), pmt::from_long(errors));

    message_port_pub(
        pmt::mp("out"),
        pmt::cons(meta, pmt::init_u8vector(d_output_frame.size(), d_output_frame)));
}

} /* namespace satellites */
} /* namespace gr */