aboutsummaryrefslogtreecommitdiff
path: root/source/codes/ReedSolomon.mc
diff options
context:
space:
mode:
authorcirakg <cirakg@cirakg.xyz>2026-10-20 06:56:58 +0200
committercirakg <cirakg@cirakg.xyz>2026-10-20 06:56:58 +0200
commit3548312586aeafbfca0d0b87db90f9bdd972c831 (patch)
treeb657f5b2884ffc506c2d9dd080407e5c6218edee /source/codes/ReedSolomon.mc
parente3cc458d3b9aadb9459b51ef0120621408093f38 (diff)
feat(codes): add a QR Code encoder (versions 1-40, levels L-H) as a resumable job
Optimal numeric/alphanumeric/byte segmentation, Reed-Solomon over GF(256), all eight masks scored like segno, steps sized for the 120,000-bytecode watchdog; block tables generated from segno; a generic Matrix type with a compact form for caching. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'source/codes/ReedSolomon.mc')
-rw-r--r--source/codes/ReedSolomon.mc110
1 files changed, 110 insertions, 0 deletions
diff --git a/source/codes/ReedSolomon.mc b/source/codes/ReedSolomon.mc
new file mode 100644
index 0000000..a69fb1a
--- /dev/null
+++ b/source/codes/ReedSolomon.mc
@@ -0,0 +1,110 @@
+// Author: cirakg & claude ai
+// Summary: Reed-Solomon error-correction codewords over GF(2^m) for QR (and later Data Matrix and Aztec).
+//
+// A Field is GF(2^m) with a primitive polynomial and the exponent the
+// generator's roots start at (QR: 0x11D, base 0; Data Matrix: 0x12D,
+// base 1). Generator polynomials are cached per field and length. ecc()
+// is the remainder of data * x^n divided by the generator: the standard
+// systematic encoding, one multiply-accumulate per data symbol and EC
+// symbol, so a caller budgets blocks per job step.
+
+import Toybox.Lang;
+
+module ReedSolomon {
+
+ class Field {
+ var size as Number;
+ var exp as Array<Number>;
+ var log as Array<Number>;
+ var base as Number;
+ private var _generators as Dictionary<Number, Array<Number>> = {} as Dictionary<Number, Array<Number>>;
+
+ // primitive: the field polynomial including x^m (0x11D for GF(256)).
+ function initialize(primitive as Number, fieldSize as Number, generatorBase as Number) {
+ size = fieldSize;
+ base = generatorBase;
+ exp = new [2 * fieldSize] as Array<Number>;
+ log = new [fieldSize] as Array<Number>;
+ var x = 1;
+ for (var i = 0; i < fieldSize - 1; i++) {
+ exp[i] = x;
+ log[x] = i;
+ x <<= 1;
+ if (x >= fieldSize) {
+ x ^= primitive;
+ }
+ }
+ // Doubled table: exp[a + b] needs no modulo.
+ for (var i = fieldSize - 1; i < 2 * fieldSize; i++) {
+ exp[i] = exp[i - (fieldSize - 1)];
+ }
+ log[0] = 0;
+ }
+
+ function multiply(a as Number, b as Number) as Number {
+ if (a == 0 || b == 0) {
+ return 0;
+ }
+ return exp[log[a] + log[b]];
+ }
+
+ // Coefficients of the generator with n roots, highest degree first,
+ // without the leading 1.
+ function generator(n as Number) as Array<Number> {
+ var cached = _generators[n];
+ if (cached != null) {
+ return cached;
+ }
+ var g = [1] as Array<Number>;
+ for (var i = 0; i < n; i++) {
+ // Multiply by (x - a^(base + i)); in GF(2^m) minus is plus.
+ var root = exp[(base + i) % (size - 1)];
+ var next = new [g.size() + 1] as Array<Number>;
+ for (var k = 0; k < next.size(); k++) {
+ next[k] = 0;
+ }
+ for (var k = 0; k < g.size(); k++) {
+ next[k] = next[k] ^ g[k];
+ next[k + 1] = next[k + 1] ^ multiply(g[k], root);
+ }
+ g = next;
+ }
+ var coefficients = g.slice(1, null) as Array<Number>;
+ _generators[n] = coefficients;
+ return coefficients;
+ }
+ }
+
+ // The n error-correction symbols of data (both as symbol values).
+ function ecc(field as Field, data as Array<Number>, n as Number) as Array<Number> {
+ var g = field.generator(n);
+ var rem = new [n] as Array<Number>;
+ for (var k = 0; k < n; k++) {
+ rem[k] = 0;
+ }
+ var exp = field.exp;
+ var log = field.log;
+ var logG = new [n] as Array<Number>;
+ for (var k = 0; k < n; k++) {
+ logG[k] = g[k] == 0 ? -1 : log[g[k]];
+ }
+ for (var i = 0; i < data.size(); i++) {
+ var factor = data[i] ^ rem[0];
+ // Shift the remainder left by one symbol.
+ for (var k = 0; k < n - 1; k++) {
+ rem[k] = rem[k + 1];
+ }
+ rem[n - 1] = 0;
+ if (factor != 0) {
+ var lf = log[factor];
+ for (var k = 0; k < n; k++) {
+ var lg = logG[k];
+ if (lg >= 0) {
+ rem[k] = rem[k] ^ exp[lf + lg];
+ }
+ }
+ }
+ }
+ return rem;
+ }
+}