TinyModem
Header-only software audio modem library
Loading...
Searching...
No Matches
ReedSolomon.h
Go to the documentation of this file.
1#pragma once
2
3#include <stdint.h>
4#include <string.h>
5
6#include "AudioTools.h"
7
8namespace tinymodem {
9
18class RSCodec {
19 public:
21 static constexpr int MAX_LEN = 255;
24 static constexpr int MAX_ECC = 64;
25
28 static void encode(const uint8_t* msg, int len, int ecc, uint8_t* out,
29 int fcr = 0) {
30 if (ecc < 1 || ecc > MAX_ECC || len + ecc > MAX_LEN) {
31 LOGE("RSCodec: invalid length %d + %d", len, ecc);
32 return;
33 }
34 uint8_t gen[MAX_ECC + 1];
35 generator(ecc, gen, fcr);
36 uint8_t work[MAX_LEN];
37 memcpy(work, msg, len);
38 memset(work + len, 0, ecc);
39 // polynomial division: the remainder are the parity bytes
40 for (int i = 0; i < len; i++) {
41 uint8_t coef = work[i];
42 if (coef == 0) continue;
43 for (int j = 1; j <= ecc; j++) work[i + j] ^= mul(gen[j], coef);
44 }
45 memcpy(out, msg, len);
46 memcpy(out + len, work + len, ecc);
47 }
48
51 static bool decode(uint8_t* data, int len, int ecc, int fcr = 0) {
52 return correct(data, len, ecc, fcr) >= 0;
53 }
54
58 static int correct(uint8_t* data, int len, int ecc, int fcr = 0) {
59 int n = len + ecc;
60 if (n > MAX_LEN || ecc < 1 || ecc > MAX_ECC) return -1;
61 uint8_t synd[MAX_ECC];
62 if (!syndromes(data, n, ecc, synd, fcr)) return 0; // no errors
63
64 // Berlekamp-Massey: error locator lambda (ascending powers)
65 uint8_t lambda[MAX_ECC + 2] = {1}, prev[MAX_ECC + 2] = {1};
66 uint8_t tmp[MAX_ECC + 2];
67 int nlambda = 1, nprev = 1, L = 0, m = 1;
68 uint8_t b = 1;
69 for (int r = 0; r < ecc; r++) {
70 uint8_t d = synd[r];
71 for (int i = 1; i <= L && i < nlambda; i++)
72 d ^= mul(lambda[i], synd[r - i]);
73 if (d == 0) {
74 m++;
75 continue;
76 }
77 uint8_t coef = div(d, b);
78 bool grow = 2 * L <= r;
79 if (grow) {
80 memcpy(tmp, lambda, nlambda);
81 }
82 int ntmp = nlambda;
83 // lambda -= coef * x^m * prev
84 if (nprev + m > nlambda) {
85 memset(lambda + nlambda, 0, nprev + m - nlambda);
86 nlambda = nprev + m;
87 }
88 for (int i = 0; i < nprev; i++) lambda[i + m] ^= mul(coef, prev[i]);
89 if (grow) {
90 L = r + 1 - L;
91 memcpy(prev, tmp, ntmp);
92 nprev = ntmp;
93 b = d;
94 m = 1;
95 } else {
96 m++;
97 }
98 }
99 if (2 * L > ecc) return -1;
100
101 // Chien search: positions of the errors
102 uint8_t pos[MAX_ECC / 2 + 1];
103 int nerr = 0;
104 for (int i = 0; i < n; i++) {
105 int power = n - 1 - i;
106 uint8_t x_inv = pow2(255 - power); // alpha^-power
107 if (eval(lambda, nlambda, x_inv) == 0) {
108 if (nerr == L) return -1;
109 pos[nerr++] = i;
110 }
111 }
112 if (nerr != L) return -1;
113
114 // Forney: omega = synd * lambda mod x^ecc
115 uint8_t omega[MAX_ECC];
116 for (int i = 0; i < ecc; i++) {
117 uint8_t v = 0;
118 for (int j = 0; j <= i && j < nlambda; j++)
119 v ^= mul(lambda[j], synd[i - j]);
120 omega[i] = v;
121 }
122 for (int k = 0; k < nerr; k++) {
123 int power = n - 1 - pos[k];
124 uint8_t x = pow2(power);
125 uint8_t x_inv = pow2(255 - power);
126 // derivative of lambda: odd coefficients
127 uint8_t deriv = 0;
128 for (int i = 1; i < nlambda; i += 2)
129 deriv ^= mul(lambda[i], powOf(x_inv, i - 1));
130 if (deriv == 0) return -1;
131 // Forney: e = X^(1 - fcr) * omega(X^-1) / lambda'(X^-1)
132 uint8_t factor = pow2(((1 - fcr) * power % 255 + 255) % 255);
133 uint8_t e = mul(factor, div(eval(omega, ecc, x_inv), deriv));
134 data[pos[k]] ^= e;
135 }
136 // the corrected data must be a code word
137 return syndromes(data, n, ecc, synd, fcr) ? -1 : nerr;
138 }
139
140 protected:
141 struct Tables {
142 uint8_t exp[512];
143 uint8_t log[256];
145 int x = 1;
146 for (int i = 0; i < 255; i++) {
147 exp[i] = x;
148 log[x] = i;
149 x <<= 1;
150 if (x & 0x100) x ^= 0x11d;
151 }
152 for (int i = 255; i < 512; i++) exp[i] = exp[i - 255];
153 log[0] = 0;
154 }
155 };
156
157 static const Tables& tables() {
158 static Tables result;
159 return result;
160 }
161
162 static uint8_t mul(uint8_t a, uint8_t b) {
163 if (a == 0 || b == 0) return 0;
164 const Tables& t = tables();
165 return t.exp[t.log[a] + t.log[b]];
166 }
167
168 static uint8_t div(uint8_t a, uint8_t b) {
169 if (a == 0) return 0;
170 const Tables& t = tables();
171 return t.exp[(t.log[a] + 255 - t.log[b]) % 255];
172 }
173
175 static uint8_t pow2(int power) { return tables().exp[power % 255]; }
176
177 static uint8_t powOf(uint8_t x, int power) {
178 if (power == 0) return 1;
179 if (x == 0) return 0;
180 const Tables& t = tables();
181 return t.exp[(t.log[x] * power) % 255];
182 }
183
185 static uint8_t eval(const uint8_t* poly, int n, uint8_t x) {
186 uint8_t y = 0;
187 for (int i = n - 1; i >= 0; i--) y = mul(y, x) ^ poly[i];
188 return y;
189 }
190
192 static void generator(int ecc, uint8_t* gen, int fcr) {
193 gen[0] = 1;
194 int len = 1;
195 for (int i = 0; i < ecc; i++) {
196 // gen *= (x + alpha^(fcr + i))
197 uint8_t root = pow2(fcr + i);
198 gen[len] = 0;
199 for (int j = len; j > 0; j--) gen[j] ^= mul(gen[j - 1], root);
200 len++;
201 }
202 }
203
206 static bool syndromes(const uint8_t* data, int n, int ecc, uint8_t* synd,
207 int fcr) {
208 bool errors = false;
209 for (int j = 0; j < ecc; j++) {
210 uint8_t x = pow2(fcr + j);
211 uint8_t y = 0;
212 for (int i = 0; i < n; i++) y = mul(y, x) ^ data[i];
213 synd[j] = y;
214 if (y != 0) errors = true;
215 }
216 return errors;
217 }
218};
219
220} // namespace tinymodem
Reed-Solomon code over GF(256) with the polynomial 0x11d and lengths which are defined at runtime....
Definition ReedSolomon.h:18
static bool syndromes(const uint8_t *data, int n, int ecc, uint8_t *synd, int fcr)
Definition ReedSolomon.h:206
static void encode(const uint8_t *msg, int len, int ecc, uint8_t *out, int fcr=0)
Definition ReedSolomon.h:28
static const Tables & tables()
Definition ReedSolomon.h:157
static uint8_t eval(const uint8_t *poly, int n, uint8_t x)
Evaluates a polynomial with ascending powers.
Definition ReedSolomon.h:185
static uint8_t div(uint8_t a, uint8_t b)
Definition ReedSolomon.h:168
static constexpr int MAX_ECC
Definition ReedSolomon.h:24
static constexpr int MAX_LEN
max length of message + parity
Definition ReedSolomon.h:21
static uint8_t powOf(uint8_t x, int power)
Definition ReedSolomon.h:177
static uint8_t mul(uint8_t a, uint8_t b)
Definition ReedSolomon.h:162
static uint8_t pow2(int power)
alpha^power (power 0 - 255)
Definition ReedSolomon.h:175
static void generator(int ecc, uint8_t *gen, int fcr)
Generator polynomial (descending powers) with ecc + 1 coefficients.
Definition ReedSolomon.h:192
static bool decode(uint8_t *data, int len, int ecc, int fcr=0)
Definition ReedSolomon.h:51
static int correct(uint8_t *data, int len, int ecc, int fcr=0)
Definition ReedSolomon.h:58
TinyModem: software audio modems and packets with error correction.
Definition AX25.h:11
Definition ReedSolomon.h:141
uint8_t exp[512]
Definition ReedSolomon.h:142
Tables()
Definition ReedSolomon.h:144
uint8_t log[256]
Definition ReedSolomon.h:143