// // This file is part of Dire Wolf, an amateur radio packet TNC. // // Copyright (C) 2019 John Langner, WB2OSZ // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // ----------------------------------------------------------------------- // // This is based on: // // // FX25_extract.c // Author: Jim McGuire KB3MPL // Date: 23 October 2007 // // // Accepts an FX.25 byte stream on STDIN, finds the correlation tag, stores 256 bytes, // corrects errors with FEC, removes the bit-stuffing, and outputs the resultant AX.25 // byte stream out STDOUT. // // stdout prints a bunch of status information about the packet being processed. // // // Usage : FX25_extract < infile > outfile [2> logfile] // // // // This program is a single-file implementation of the FX.25 extraction/decode // structure for use with FX.25 data frames. Details of the FX.25 // specification are available at: // http://www.stensat.org/Docs/Docs.htm // // This program implements a single RS(255,239) FEC structure. Future // releases will incorporate more capabilities as accommodated in the FX.25 // spec. // // The Reed Solomon encoding routines are based on work performed by // Phil Karn. Phil was kind enough to release his code under the GPL, as // noted below. Consequently, this FX.25 implementation is also released // under the terms of the GPL. // // Phil Karn's original copyright notice: /* Test the Reed-Solomon codecs * for various block sizes and with random data and random error patterns * * Copyright 2002 Phil Karn, KA9Q * May be used under the terms of the GNU General Public License (GPL) * */ #include #include #include #include "fx25.h" //#define DEBUG 5 //----------------------------------------------------------------------- // Revision History //----------------------------------------------------------------------- // 0.0.1 - initial release // Modifications from Phil Karn's GPL source code. // Initially added code to run with PC file // I/O and use the (255,239) decoder exclusively. Confirmed that the // code produces the correct results. // //----------------------------------------------------------------------- // 0.0.2 - #define min(a,b) ((a) < (b) ? (a) : (b)) int DECODE_RS(struct rs * restrict rs, DTYPE * restrict data, int *eras_pos, int no_eras) { int deg_lambda, el, deg_omega; int i, j, r,k; DTYPE u,q,tmp,num1,num2,den,discr_r; // DTYPE lambda[NROOTS+1], s[NROOTS]; /* Err+Eras Locator poly and syndrome poly */ // DTYPE b[NROOTS+1], t[NROOTS+1], omega[NROOTS+1]; // DTYPE root[NROOTS], reg[NROOTS+1], loc[NROOTS]; DTYPE lambda[FX25_MAX_CHECK+1], s[FX25_MAX_CHECK]; /* Err+Eras Locator poly and syndrome poly */ DTYPE b[FX25_MAX_CHECK+1], t[FX25_MAX_CHECK+1], omega[FX25_MAX_CHECK+1]; DTYPE root[FX25_MAX_CHECK], reg[FX25_MAX_CHECK+1], loc[FX25_MAX_CHECK]; int syn_error, count; /* form the syndromes; i.e., evaluate data(x) at roots of g(x) */ for(i=0;i 0) { /* Init lambda to be the erasure locator polynomial */ lambda[1] = ALPHA_TO[MODNN(PRIM*(NN-1-eras_pos[0]))]; for (i = 1; i < no_eras; i++) { u = MODNN(PRIM*(NN-1-eras_pos[i])); for (j = i+1; j > 0; j--) { tmp = INDEX_OF[lambda[j - 1]]; if(tmp != A0) lambda[j] ^= ALPHA_TO[MODNN(u + tmp)]; } } #if DEBUG >= 1 /* Test code that verifies the erasure locator polynomial just constructed Needed only for decoder debugging. */ /* find roots of the erasure location polynomial */ for(i=1;i<=no_eras;i++) reg[i] = INDEX_OF[lambda[i]]; count = 0; for (i = 1,k=IPRIM-1; i <= NN; i++,k = MODNN(k+IPRIM)) { q = 1; for (j = 1; j <= no_eras; j++) if (reg[j] != A0) { reg[j] = MODNN(reg[j] + j); q ^= ALPHA_TO[reg[j]]; } if (q != 0) continue; /* store root and error location number indices */ root[count] = i; loc[count] = k; count++; } if (count != no_eras) { fprintf(stderr,"count = %d no_eras = %d\n lambda(x) is WRONG\n",count,no_eras); count = -1; goto finish; } #if DEBUG >= 2 fprintf(stderr,"\n Erasure positions as determined by roots of Eras Loc Poly:\n"); for (i = 0; i < count; i++) fprintf(stderr,"%d ", loc[i]); fprintf(stderr,"\n"); #endif #endif } for(i=0;i 0; j--){ if (reg[j] != A0) { reg[j] = MODNN(reg[j] + j); q ^= ALPHA_TO[reg[j]]; } } if (q != 0) continue; /* Not a root */ /* store root (index-form) and error location number */ #if DEBUG>=2 fprintf(stderr,"count %d root %d loc %d\n",count,i,k); #endif root[count] = i; loc[count] = k; /* If we've already found max possible roots, * abort the search to save time */ if(++count == deg_lambda) break; } if (deg_lambda != count) { /* * deg(lambda) unequal to number of roots => uncorrectable * error detected */ count = -1; goto finish; } /* * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo * x**NROOTS). in index form. Also find deg(omega). */ deg_omega = 0; for (i = 0; i < NROOTS;i++){ tmp = 0; j = (deg_lambda < i) ? deg_lambda : i; for(;j >= 0; j--){ if ((s[i - j] != A0) && (lambda[j] != A0)) tmp ^= ALPHA_TO[MODNN(s[i - j] + lambda[j])]; } if(tmp != 0) deg_omega = i; omega[i] = INDEX_OF[tmp]; } omega[NROOTS] = A0; /* * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 = * inv(X(l))**(FCR-1) and den = lambda_pr(inv(X(l))) all in poly-form */ for (j = count-1; j >=0; j--) { num1 = 0; for (i = deg_omega; i >= 0; i--) { if (omega[i] != A0) num1 ^= ALPHA_TO[MODNN(omega[i] + i * root[j])]; } num2 = ALPHA_TO[MODNN(root[j] * (FCR - 1) + NN)]; den = 0; /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */ for (i = min(deg_lambda,NROOTS-1) & ~1; i >= 0; i -=2) { if(lambda[i+1] != A0) den ^= ALPHA_TO[MODNN(lambda[i+1] + i * root[j])]; } if (den == 0) { #if DEBUG >= 1 fprintf(stderr,"\n ERROR: denominator = 0\n"); #endif count = -1; goto finish; } /* Apply error to data */ if (num1 != 0) { data[loc[j]] ^= ALPHA_TO[MODNN(INDEX_OF[num1] + INDEX_OF[num2] + NN - INDEX_OF[den])]; } } finish: if(eras_pos != NULL){ for(i=0;i