diff --git a/Modem.cpp b/Modem.cpp index 30d355d..c272626 100644 --- a/Modem.cpp +++ b/Modem.cpp @@ -562,7 +562,7 @@ void CModem::clock(unsigned int ms) m_txP25Data.getData(m_buffer, len); if (m_debug) { - if (m_buffer[3U] == MMDVM_P25_HDR) + if (m_buffer[2U] == MMDVM_P25_HDR) CUtils::dump(1U, "TX P25 HDR", m_buffer, len); else CUtils::dump(1U, "TX P25 LDU", m_buffer, len); diff --git a/RS.cpp b/RS.cpp index 8c8208f..71174d9 100644 --- a/RS.cpp +++ b/RS.cpp @@ -17,6 +17,7 @@ */ #include "RS.h" +#include "Log.h" #include #include @@ -91,8 +92,10 @@ bool CRS362017::decode(unsigned char* data) // Now we can call decode on the base class int irrecoverable_errors = CReedSolomon63<8>::decode(input, output); - if (irrecoverable_errors != 0) + if (irrecoverable_errors != 0) { + LogWarning("Unrecoverable errors in the RS(36,20,17) code"); return false; + } // Convert it back to binary and put it into hex_data. offset = 0U; @@ -168,8 +171,10 @@ bool CRS241213::decode(unsigned char* data) // Now we can call decode on the base class int irrecoverable_errors = CReedSolomon63<6>::decode(input, output); - if (irrecoverable_errors != 0) + if (irrecoverable_errors != 0) { + LogWarning("Unrecoverable errors in the RS(24,12,13) code"); return false; + } // Convert it back to binary and put it into hex_data. offset = 0U; @@ -245,8 +250,10 @@ bool CRS24169::decode(unsigned char* data) // Now we can call decode on the base class int irrecoverable_errors = CReedSolomon63<4>::decode(input, output); - if (irrecoverable_errors != 0) + if (irrecoverable_errors != 0) { + LogWarning("Unrecoverable errors in the RS(24,16,9) code"); return false; + } // Convert it back to binary and put it into hex_data. offset = 0U; diff --git a/RS.h b/RS.h index a38e6b0..beffa32 100644 --- a/RS.h +++ b/RS.h @@ -61,79 +61,98 @@ Simon Rockliff, 26th June 1991 template class CReedSolomon63 { private: - static const int MM = 6; /* RS code over GF(2**mm) */ - static const int NN = 63; /* nn=2**mm -1 length of codeword */ - //int tt; /* number of errors that can be corrected */ - //int kk; /* kk = nn-2*tt */ + static const int MM = 6; // RS code over GF(2**mm) + static const int NN = 63; // nn=2**mm -1 length of codeword + //int tt; number of errors that can be corrected + //int kk; kk = nn-2*tt static const int KK = NN - 2 * TT; // distance = nn-kk+1 = 2*tt+1 - int* alpha_to; - int* index_of; int* gg; - void generate_gf(int* generator_polinomial) - /* generate GF(2**mm) from the irreducible polynomial p(X) in pp[0]..pp[mm] - lookup tables: index->polynomial form alpha_to[] contains j=alpha**i; - polynomial form -> index form index_of[j=alpha**i] = i - alpha=2 is the primitive element of GF(2**mm) - */ + // generate GF(2**mm) from the irreducible polynomial p(X) in pp[0]..pp[mm] + // lookup tables: index->polynomial form alpha_to[] contains j=alpha**i; + // polynomial form -> index form index_of[j=alpha**i] = i + // alpha=2 is the primitive element of GF(2**mm) + void generate_gf(const int* generator_polinomial) { register int i, mask; mask = 1; alpha_to[MM] = 0; + for (i = 0; i < MM; i++) { alpha_to[i] = mask; index_of[alpha_to[i]] = i; + if (generator_polinomial[i] != 0) alpha_to[MM] ^= mask; + mask <<= 1; } + index_of[alpha_to[MM]] = MM; + mask >>= 1; + for (i = MM + 1; i < NN; i++) { if (alpha_to[i - 1] >= mask) alpha_to[i] = alpha_to[MM] ^ ((alpha_to[i - 1] ^ mask) << 1); else alpha_to[i] = alpha_to[i - 1] << 1; + index_of[alpha_to[i]] = i; } + index_of[0] = -1; } + // Obtain the generator polynomial of the tt-error correcting, length + // nn=(2**mm -1) Reed Solomon code from the product of (X+alpha**i), i=1..2*tt void gen_poly() - /* Obtain the generator polynomial of the tt-error correcting, length - nn=(2**mm -1) Reed Solomon code from the product of (X+alpha**i), i=1..2*tt - */ { register int i, j; - gg[0] = 2; /* primitive element alpha = 2 for GF(2**mm) */ - gg[1] = 1; /* g(x) = (X+alpha) initially */ + gg[0] = 2; // primitive element alpha = 2 for GF(2**mm) + gg[1] = 1; // g(x) = (X+alpha) initially + for (i = 2; i <= NN - KK; i++) { gg[i] = 1; + for (j = i - 1; j > 0; j--) if (gg[j] != 0) gg[j] = gg[j - 1] ^ alpha_to[(index_of[gg[j]] + i) % NN]; else gg[j] = gg[j - 1]; - gg[0] = alpha_to[(index_of[gg[0]] + i) % NN]; /* gg[0] can never be zero */ + + gg[0] = alpha_to[(index_of[gg[0]] + i) % NN]; // gg[0] can never be zero } - /* convert gg[] to index form for quicker encoding */ + + // convert gg[] to index form for quicker encoding for (i = 0; i <= NN - KK; i++) gg[i] = index_of[gg[i]]; } -public: +protected: + int* alpha_to; + int* index_of; + CReedSolomon63() { alpha_to = new int[NN + 1]; index_of = new int[NN + 1]; gg = new int[NN - KK + 1]; + for (unsigned int i = 0U; i < (NN + 1); i++) { + alpha_to[i] = 0; + index_of[i] = 0; + } + + for (unsigned int i = 0U; i < (NN - KK + 1); i++) + gg[i] = 0; + // Polynom used in P25 is alpha**6+alpha+1 - int generator_polinomial[] = { 1, 1, 0, 0, 0, 0, 1 }; /* specify irreducible polynomial coeffts */ + const int generator_polinomial[] = {1, 1, 0, 0, 0, 0, 1}; // specify irreducible polynomial coeffts generate_gf(generator_polinomial); @@ -147,19 +166,20 @@ public: delete[] alpha_to; } + // take the string of symbols in data[i], i=0..(k-1) and encode systematically + // to produce 2*tt parity symbols in bb[0]..bb[2*tt-1] + // data[] is input and bb[] is output in polynomial form. + // Encoding is done by using a feedback shift register with appropriate + // connections specified by the elements of gg[], which was generated above. + // Codeword is c(X) = data(X)*X**(nn-kk)+ b(X) void encode(const int* data, int* bb) - /* take the string of symbols in data[i], i=0..(k-1) and encode systematically - to produce 2*tt parity symbols in bb[0]..bb[2*tt-1] - data[] is input and bb[] is output in polynomial form. - Encoding is done by using a feedback shift register with appropriate - connections specified by the elements of gg[], which was generated above. - Codeword is c(X) = data(X)*X**(nn-kk)+ b(X) */ { register int i, j; int feedback; for (i = 0; i < NN - KK; i++) bb[i] = 0; + for (i = KK - 1; i >= 0; i--) { feedback = index_of[data[i] ^ bb[NN - KK - 1]]; if (feedback != -1) { @@ -168,41 +188,40 @@ public: bb[j] = bb[j - 1] ^ alpha_to[(gg[j] + feedback) % NN]; else bb[j] = bb[j - 1]; + bb[0] = alpha_to[(gg[0] + feedback) % NN]; - } - else { + } else { for (j = NN - KK - 1; j > 0; j--) bb[j] = bb[j - 1]; + bb[0] = 0; } } } + /* assume we have received bits grouped into mm-bit symbols in recd[i], + i=0..(nn-1), and recd[i] is polynomial form. + We first compute the 2*tt syndromes by substituting alpha**i into rec(X) and + evaluating, storing the syndromes in s[i], i=1..2tt (leave s[0] zero) . + Then we use the Berlekamp iteration to find the error location polynomial + elp[i]. If the degree of the elp is >tt, we cannot correct all the errors + and hence just put out the information symbols uncorrected. If the degree of + elp is <=tt, we substitute alpha**i , i=1..n into the elp to get the roots, + hence the inverse roots, the error location numbers. If the number of errors + located does not equal the degree of the elp, we have more than tt errors + and cannot correct them. Otherwise, we then solve for the error value at + the error location and correct the error. The procedure is that found in + Lin and Costello. For the cases where the number of errors is known to be too + large to correct, the information symbols as received are output (the + advantage of systematic encoding is that hopefully some of the information + symbols will be okay and that if we are in luck, the errors are in the + parity part of the transmitted codeword). Of course, these insoluble cases + can be returned as error flags to the calling routine if desired. */ int decode(const int* input, int* recd) - /* assume we have received bits grouped into mm-bit symbols in recd[i], - i=0..(nn-1), and recd[i] is polynomial form. - We first compute the 2*tt syndromes by substituting alpha**i into rec(X) and - evaluating, storing the syndromes in s[i], i=1..2tt (leave s[0] zero) . - Then we use the Berlekamp iteration to find the error location polynomial - elp[i]. If the degree of the elp is >tt, we cannot correct all the errors - and hence just put out the information symbols uncorrected. If the degree of - elp is <=tt, we substitute alpha**i , i=1..n into the elp to get the roots, - hence the inverse roots, the error location numbers. If the number of errors - located does not equal the degree of the elp, we have more than tt errors - and cannot correct them. Otherwise, we then solve for the error value at - the error location and correct the error. The procedure is that found in - Lin and Costello. For the cases where the number of errors is known to be too - large to correct, the information symbols as received are output (the - advantage of systematic encoding is that hopefully some of the information - symbols will be okay and that if we are in luck, the errors are in the - parity part of the transmitted codeword). Of course, these insoluble cases - can be returned as error flags to the calling routine if desired. */ { register int i, j, u, q; - int elp[NN - KK + 2][NN - KK], d[NN - KK + 2], l[NN - KK + 2], u_lu[NN - KK - + 2], s[NN - KK + 1]; - int count = 0, syn_error = 0, root[TT], loc[TT], z[TT + 1], err[NN], reg[TT - + 1]; + int elp[NN - KK + 2][NN - KK], d[NN - KK + 2], l[NN - KK + 2], u_lu[NN - KK + 2], s[NN - KK + 1]; + int count = 0, syn_error = 0, root[TT], loc[TT], z[TT + 1], err[NN], reg[TT + 1]; int irrecoverable_error = 0; @@ -212,12 +231,15 @@ public: /* first form the syndromes */ for (i = 1; i <= NN - KK; i++) { s[i] = 0; + for (j = 0; j < NN; j++) if (recd[j] != -1) s[i] ^= alpha_to[(recd[j] + i * j) % NN]; /* recd[j] in index form */ /* convert syndrome from polynomial form to index form */ + if (s[i] != 0) syn_error = 1; /* set flag if non-zero syndrome => error */ + s[i] = index_of[s[i]]; } @@ -230,15 +252,18 @@ public: degree of the elp at that step, and u_l[u] is the difference between the step number and the degree of the elp. */ + /* initialise table entries */ d[0] = 0; /* index form */ d[1] = s[1]; /* index form */ elp[0][0] = 0; /* index form */ elp[1][0] = 1; /* polynomial form */ + for (i = 1; i < NN - KK; i++) { elp[0][i] = -1; /* index form */ elp[1][i] = 0; /* polynomial form */ } + l[0] = 0; l[1] = 0; u_lu[0] = -1; @@ -247,19 +272,21 @@ public: do { u++; + if (d[u] == -1) { l[u + 1] = l[u]; + for (i = 0; i <= l[u]; i++) { elp[u + 1][i] = elp[u][i]; elp[u][i] = index_of[elp[u][i]]; } - } - else + } else /* search for words with greatest u_lu[q] for which d[q]!=0 */ { q = u - 1; while ((d[q] == -1) && (q > 0)) q--; + /* have found first non-zero d[q] */ if (q > 0) { j = q; @@ -280,15 +307,17 @@ public: /* form new elp(x) */ for (i = 0; i < NN - KK; i++) elp[u + 1][i] = 0; + for (i = 0; i <= l[q]; i++) if (elp[q][i] != -1) - elp[u + 1][i + u - q] = alpha_to[(d[u] + NN - d[q] - + elp[q][i]) % NN]; + elp[u + 1][i + u - q] = alpha_to[(d[u] + NN - d[q] + elp[q][i]) % NN]; + for (i = 0; i <= l[u]; i++) { elp[u + 1][i] ^= elp[u][i]; elp[u][i] = index_of[elp[u][i]]; /*convert old elp value to index*/ } } + u_lu[u + 1] = u - l[u + 1]; /* form (u+1)th discrepancy */ @@ -298,10 +327,12 @@ public: d[u + 1] = alpha_to[s[u + 1]]; else d[u + 1] = 0; + for (i = 1; i <= l[u + 1]; i++) if ((s[u + 1 - i] != -1) && (elp[u + 1][i] != 0)) d[u + 1] ^= alpha_to[(s[u + 1 - i] + index_of[elp[u + 1][i]]) % NN]; + d[u + 1] = index_of[d[u + 1]]; /* put d[u+1] into index form */ } } while ((u < NN - KK) && (l[u + 1] <= TT)); @@ -316,14 +347,18 @@ public: /* find roots of the error location polynomial */ for (i = 1; i <= l[u]; i++) reg[i] = elp[u][i]; + count = 0; + for (i = 1; i <= NN; i++) { q = 1; + for (j = 1; j <= l[u]; j++) if (reg[j] != -1) { reg[j] = (reg[j] + j) % NN; q ^= alpha_to[reg[j]]; }; + if (!q) /* store root and error location number indices */ { root[count] = i; @@ -345,9 +380,11 @@ public: z[i] = alpha_to[elp[u][i]]; else z[i] = 0; + for (j = 1; j < i; j++) if ((s[j] != -1) && (elp[u][i - j] != -1)) z[i] ^= alpha_to[(elp[u][i - j] + s[j]) % NN]; + z[i] = index_of[z[i]]; /* put into index form */ }; @@ -359,38 +396,39 @@ public: else recd[i] = 0; } + for (i = 0; i < l[u]; i++) /* compute numerator of error term first */ { err[loc[i]] = 1; /* accounts for z[0] */ + for (j = 1; j <= l[u]; j++) if (z[j] != -1) err[loc[i]] ^= alpha_to[(z[j] + j * root[i]) % NN]; + if (err[loc[i]] != 0) { err[loc[i]] = index_of[err[loc[i]]]; q = 0; /* form denominator of error term */ + for (j = 0; j < l[u]; j++) if (j != i) - q += index_of[1 - ^ alpha_to[(loc[j] + root[i]) % NN]]; + q += index_of[1 ^ alpha_to[(loc[j] + root[i]) % NN]]; + q = q % NN; err[loc[i]] = alpha_to[(err[loc[i]] - q + NN) % NN]; recd[loc[i]] ^= err[loc[i]]; /*recd[i] must be in polynomial form */ } } - } - else { + } else { /* no. roots != degree of elp => >tt errors and cannot solve */ irrecoverable_error = 1; } - } - else { + } else { /* elp has degree >tt hence cannot solve */ irrecoverable_error = 1; } - } - else { + } else { /* no non-zero syndromes => no errors: output received codeword */ for (i = 0; i < NN; i++) if (recd[i] != -1) /* convert recd[] to polynomial form */ @@ -411,10 +449,6 @@ public: } }; -/** -* Convenience class that does a Reed-Solomon (36,20,17) error correction adapting input and output to -* the DSD data format: hex words packed as char arrays. -*/ class CRS362017 : public CReedSolomon63<8> { public: @@ -428,10 +462,6 @@ public: private: }; -/** -* Convenience class that does a Reed-Solomon (24,12,13) error correction adapting input and output to -* the DSD data format: hex words packed as char arrays. -*/ class CRS241213 : public CReedSolomon63<6> { public: @@ -445,10 +475,6 @@ public: private: }; -/** -* Convenience class that does a Reed-Solomon (24,16,9) error correction adapting input and output to -* the DSD data format: hex words packed as char arrays. -*/ class CRS24169 : public CReedSolomon63<4> { public: