From 614ee83f08899045b6ab4154582188ec716f129b Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Tue, 27 Sep 2016 18:36:08 +0100 Subject: [PATCH] Add LDU1 Reed-Solomon encoding and decoding. --- MMDVMHost.vcxproj | 4 +- MMDVMHost.vcxproj.filters | 8 +- Makefile | 4 +- Makefile.Pi.Adafruit | 4 +- Makefile.Pi.HD44780 | 4 +- Makefile.Pi.OLED | 4 +- Makefile.Pi.PCF8574 | 4 +- Makefile.Solaris | 4 +- P25Data.cpp | 20 +- P25Data.h | 4 +- RS.cpp | 289 ---------------------- RS.h | 491 -------------------------------------- RS241213.cpp | 370 ++++++++++++++++++++++++++++ RS241213.h | 36 +++ 14 files changed, 436 insertions(+), 810 deletions(-) delete mode 100644 RS.cpp delete mode 100644 RS.h create mode 100644 RS241213.cpp create mode 100644 RS241213.h diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj index ff38eb5..87db1a4 100644 --- a/MMDVMHost.vcxproj +++ b/MMDVMHost.vcxproj @@ -192,8 +192,8 @@ - + @@ -253,8 +253,8 @@ - + diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters index 59775be..a189600 100644 --- a/MMDVMHost.vcxproj.filters +++ b/MMDVMHost.vcxproj.filters @@ -197,10 +197,10 @@ Header Files - + Header Files - + Header Files @@ -370,10 +370,10 @@ Source Files - + Source Files - + Source Files diff --git a/Makefile b/Makefile index 6cbcfbc..ca7d2ad 100644 --- a/Makefile +++ b/Makefile @@ -10,8 +10,8 @@ OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedLC.o DMRFullLC.o DMRLookup.o DMRLC.o \ DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \ Golay24128.o Hamming.o Log.o MMDVMHost.o Modem.o Nextion.o NullDisplay.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Utils.o \ - QR1676.o RS.o RS129.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o \ - YSFNetwork.o YSFPayload.o + QR1676.o RS129.o RS241213.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o Utils.o YSFControl.o YSFConvolution.o \ + YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost diff --git a/Makefile.Pi.Adafruit b/Makefile.Pi.Adafruit index 52ee6fd..f1802d9 100644 --- a/Makefile.Pi.Adafruit +++ b/Makefile.Pi.Adafruit @@ -10,8 +10,8 @@ OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedLC.o DMRFullLC.o DMRLookup.o DMRLC.o \ DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \ Golay24128.o Hamming.o HD44780.o Log.o MMDVMHost.o Modem.o Nextion.o NullDisplay.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o \ - P25Utils.o QR1676.o RS.o RS129.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o Utils.o YSFControl.o YSFConvolution.o \ - YSFFICH.o YSFNetwork.o YSFPayload.o + P25Utils.o QR1676.o RS129.o RS241213.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o Utils.o YSFControl.o \ + YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost diff --git a/Makefile.Pi.HD44780 b/Makefile.Pi.HD44780 index 84e0598..6a778d5 100644 --- a/Makefile.Pi.HD44780 +++ b/Makefile.Pi.HD44780 @@ -10,8 +10,8 @@ OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedLC.o DMRFullLC.o DMRLookup.o DMRLC.o \ DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \ Golay24128.o Hamming.o HD44780.o Log.o MMDVMHost.o Modem.o Nextion.o NullDisplay.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o \ - P25Utils.o QR1676.o RS.o RS129.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o Utils.o YSFControl.o YSFConvolution.o \ - YSFFICH.o YSFNetwork.o YSFPayload.o + P25Utils.o QR1676.o RS129.o RS241213.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o Utils.o YSFControl.o \ + YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED index 762390c..a0a599c 100644 --- a/Makefile.Pi.OLED +++ b/Makefile.Pi.OLED @@ -10,8 +10,8 @@ OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedLC.o DMRFullLC.o DMRLookup.o DMRLC.o \ DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \ Golay24128.o Hamming.o OLED.o Log.o MMDVMHost.o Modem.o Nextion.o NullDisplay.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o \ - P25Utils.o QR1676.o RS.o RS129.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o Utils.o YSFControl.o YSFConvolution.o \ - YSFFICH.o YSFNetwork.o YSFPayload.o + P25Utils.o QR1676.o RS129.o RS241213.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o Utils.o YSFControl.o \ + YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost diff --git a/Makefile.Pi.PCF8574 b/Makefile.Pi.PCF8574 index 7bf174c..c0f0ab5 100644 --- a/Makefile.Pi.PCF8574 +++ b/Makefile.Pi.PCF8574 @@ -10,8 +10,8 @@ OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedLC.o DMRFullLC.o DMRLookup.o DMRLC.o \ DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \ Golay24128.o Hamming.o HD44780.o Log.o MMDVMHost.o Modem.o Nextion.o NullDisplay.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o \ - P25Utils.o QR1676.o RS.o RS129.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o Utils.o YSFControl.o YSFConvolution.o \ - YSFFICH.o YSFNetwork.o YSFPayload.o + P25Utils.o QR1676.o RS129.o RS241213.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o Utils.o YSFControl.o \ + YSFConvolution.o YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost diff --git a/Makefile.Solaris b/Makefile.Solaris index d4b43c0..c0d6836 100644 --- a/Makefile.Solaris +++ b/Makefile.Solaris @@ -10,8 +10,8 @@ OBJECTS = \ AMBEFEC.o BCH.o BPTC19696.o Conf.o CRC.o Display.o DMRControl.o DMRCSBK.o DMRData.o DMRDataHeader.o DMREMB.o DMREmbeddedLC.o DMRFullLC.o DMRLookup.o DMRLC.o \ DMRNetwork.o DMRShortLC.o DMRSlot.o DMRSlotType.o DMRAccessControl.o DMRTrellis.o DStarControl.o DStarHeader.o DStarNetwork.o DStarSlowData.o Golay2087.o \ Golay24128.o Hamming.o Log.o MMDVMHost.o Modem.o Nextion.o NullDisplay.o P25Audio.o P25Control.o P25Data.o P25LowSpeedData.o P25Network.o P25NID.o P25Utils.o \ - QR1676.o RS.o RS129.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o Utils.o YSFControl.o YSFConvolution.o YSFFICH.o \ - YSFNetwork.o YSFPayload.o + QR1676.o RS129.o RS241213.o SerialController.o SHA256.o StopWatch.o Sync.o TFTSerial.o Thread.o Timer.o UDPSocket.o Utils.o YSFControl.o YSFConvolution.o \ + YSFFICH.o YSFNetwork.o YSFPayload.o all: MMDVMHost diff --git a/P25Data.cpp b/P25Data.cpp index b27af06..6b97a54 100644 --- a/P25Data.cpp +++ b/P25Data.cpp @@ -71,7 +71,7 @@ void CP25Data::encodeHeader(unsigned char* data) CP25Utils::encode(DUMMY_HEADER, data, 114U, 780U); } -void CP25Data::processLDU1(unsigned char* data) +bool CP25Data::processLDU1(unsigned char* data) { assert(data != NULL); @@ -96,9 +96,11 @@ void CP25Data::processLDU1(unsigned char* data) CP25Utils::decode(data, raw, 1356U, 1398U); decodeLDUHamming(raw, rs + 15U); - // CUtils::dump(1U, "P25, LDU1 Data before", rs, 18U); - - m_rs241213.decode(rs); + bool ret = m_rs241213.decode(rs); + if (!ret) { + LogDebug("P25, uncorrectable errors in the RS(24,12,13) code"); + return false; + } m_lcf = rs[0U]; m_mfId = rs[1U]; @@ -119,9 +121,7 @@ void CP25Data::processLDU1(unsigned char* data) break; } - // m_rs241213.encode(rs); - - // CUtils::dump(1U, "P25, LDU1 Data after", rs, 18U); + m_rs241213.encode(rs); encodeLDUHamming(raw, rs + 0U); CP25Utils::encode(raw, data, 410U, 452U); @@ -140,6 +140,8 @@ void CP25Data::processLDU1(unsigned char* data) encodeLDUHamming(raw, rs + 15U); CP25Utils::encode(raw, data, 1356U, 1398U); + + return true; } void CP25Data::encodeLDU1(unsigned char* data) @@ -174,9 +176,7 @@ void CP25Data::encodeLDU1(unsigned char* data) break; } - // m_rs241213.encode(rs); - - // CUtils::dump(1U, "P25, LDU1 Data", rs, 18U); + m_rs241213.encode(rs); unsigned char raw[5U]; encodeLDUHamming(raw, rs + 0U); diff --git a/P25Data.h b/P25Data.h index 6786c62..04d044c 100644 --- a/P25Data.h +++ b/P25Data.h @@ -19,7 +19,7 @@ #if !defined(P25Data_H) #define P25Data_H -#include "RS.h" +#include "RS241213.h" class CP25Data { public: @@ -28,7 +28,7 @@ public: void encodeHeader(unsigned char* data); - void processLDU1(unsigned char* data); + bool processLDU1(unsigned char* data); void encodeLDU1(unsigned char* data); void encodeLDU2(unsigned char* data); diff --git a/RS.cpp b/RS.cpp deleted file mode 100644 index 71174d9..0000000 --- a/RS.cpp +++ /dev/null @@ -1,289 +0,0 @@ -/* -* Copyright (C) 2016 by Jonathan Naylor G4KLX -* -* 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, write to the Free Software -* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "RS.h" -#include "Log.h" - -#include -#include - -const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U }; - -#define WRITE_BIT(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7]) -#define READ_BIT(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7]) - -static int bin2Hex(const unsigned char* input, unsigned int offset) -{ - int output = 0; - - output |= READ_BIT(input, offset + 0U) ? 0x20 : 0x00; - output |= READ_BIT(input, offset + 1U) ? 0x10 : 0x00; - output |= READ_BIT(input, offset + 2U) ? 0x08 : 0x00; - output |= READ_BIT(input, offset + 3U) ? 0x04 : 0x00; - output |= READ_BIT(input, offset + 4U) ? 0x02 : 0x00; - output |= READ_BIT(input, offset + 5U) ? 0x01 : 0x00; - - return output; -} - -static void hex2Bin(int input, unsigned char* output, unsigned int offset) -{ - WRITE_BIT(output, offset + 0U, input & 0x20); - WRITE_BIT(output, offset + 1U, input & 0x10); - WRITE_BIT(output, offset + 2U, input & 0x08); - WRITE_BIT(output, offset + 3U, input & 0x04); - WRITE_BIT(output, offset + 4U, input & 0x02); - WRITE_BIT(output, offset + 5U, input & 0x01); -} - -// tt = (dd-1)/2 -// dd = 17 --> tt = 8 -CRS362017::CRS362017() : -CReedSolomon63<8>() -{ -} - -CRS362017::~CRS362017() -{ -} - -/** -* Does a Reed-Solomon decode adapting the input and output to the expected DSD data format. -* \param hex_data Data packed bits, originally a char[20][6], so containing 20 hex works, each char -* is a bit. Bits are corrected in place. -* \param hex_parity Parity packed bits, originally a char[16][6], 16 hex words. -* \return 1 if irrecoverable errors have been detected, 0 otherwise. -*/ -bool CRS362017::decode(unsigned char* data) -{ - assert(data != NULL); - - int input[63]; - int output[63]; - - // Fill up with zeros to complete the 47 expected hex words of data - for (unsigned int i = 0U; i < 63U; i++) - input[i] = 0; - - // First put the parity data, 16 hex words - unsigned int offset = 120U; - for (unsigned int i = 0U; i < 16U; i++, offset += 6U) - input[i] = bin2Hex(data, offset); - - // Then the 20 hex words of data - offset = 0U; - for (unsigned int i = 16U; i < 36U; i++, offset += 6U) - input[i] = bin2Hex(data, offset); - - // Now we can call decode on the base class - int irrecoverable_errors = CReedSolomon63<8>::decode(input, output); - 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; - for (unsigned int i = 16U; i < 36U; i++, offset += 6U) - hex2Bin(output[i], data, offset); - - return true; -} - -void CRS362017::encode(unsigned char* data) -{ - assert(data != NULL); - - int input[47]; - int output[63]; - - // Fill up with zeros to complete the 47 expected hex words of data - for (unsigned int i = 0U; i < 47U; i++) - input[i] = 0; - - // Put the 20 hex words of data - unsigned int offset = 0U; - for (unsigned int i = 0U; i < 20U; i++, offset += 6U) - input[i] = bin2Hex(data, offset); - - // Now we can call encode on the base class - CReedSolomon63<8>::encode(input, output); - - // Convert it back to binary form and put it into the parity - offset = 120U; - for (unsigned int i = 0U; i < 16U; i++, offset += 6U) - hex2Bin(output[i], data, offset); -} - -// tt = (dd-1)/2 -// dd = 13 --> tt = 6 -CRS241213::CRS241213() : -CReedSolomon63<6>() -{ -} - -CRS241213::~CRS241213() -{ -} - -/** -* Does a Reed-Solomon decode adapting the input and output to the expected DSD data format. -* \param hex_data Data packed bits, originally a char[12][6], so containing 12 hex works, each char -* is a bit. Bits are corrected in place. -* \param hex_parity Parity packed bits, originally a char[12][6], 12 hex words. -* \return 1 if irrecoverable errors have been detected, 0 otherwise. -*/ -bool CRS241213::decode(unsigned char* data) -{ - assert(data != NULL); - - int input[63]; - int output[63]; - - // Fill up with zeros to complete the 51 expected hex words of data - for (unsigned int i = 0U; i < 63U; i++) - input[i] = 0; - - // First put the parity data, 12 hex words - unsigned int offset = 72U; - for (unsigned int i = 0U; i < 12U; i++, offset += 6U) - input[i] = bin2Hex(data, offset); - - // Then the 12 hex words of data - offset = 0U; - for (unsigned int i = 12U; i < 24U; i++, offset += 6U) - input[i] = bin2Hex(data, offset); - - // Now we can call decode on the base class - int irrecoverable_errors = CReedSolomon63<6>::decode(input, output); - 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; - for (unsigned int i = 12U; i < 24U; i++, offset += 6U) - hex2Bin(output[i], data, offset); - - return true; -} - -void CRS241213::encode(unsigned char* data) -{ - assert(data != NULL); - - int input[51]; - int output[63]; - - // Fill up with zeros to complete the 51 expected hex words of data - for (unsigned int i = 0U; i < 51U; i++) - input[i] = 0; - - // Put the 12 hex words of data - unsigned int offset = 0U; - for (unsigned int i = 0U; i < 12U; i++, offset += 6U) - input[i] = bin2Hex(data, offset); - - // Now we can call encode on the base class - CReedSolomon63<6>::encode(input, output); - - // Convert it back to binary form and put it into the parity - offset = 72U; - for (unsigned int i = 0U; i < 12U; i++, offset += 6U) - hex2Bin(output[i], data, offset); -} - -// tt = (dd-1)/2 -// dd = 9 --> tt = 4 -CRS24169::CRS24169() : -CReedSolomon63<4>() -{ -} - -CRS24169::~CRS24169() -{ -} - -/** -* Does a Reed-Solomon decode adapting the input and output to the expected DSD data format. -* \param hex_data Data packed bits, originally a char[16][6], so containing 16 hex works, each char -* is a bit. Bits are corrected in place. -* \param hex_parity Parity packed bits, originally a char[8][6], 8 hex words. -* \return 1 if irrecoverable errors have been detected, 0 otherwise. -*/ -bool CRS24169::decode(unsigned char* data) -{ - assert(data != NULL); - - int input[63]; - int output[63]; - - // Fill up with zeros to complete the 55 expected hex words of data - for (unsigned int i = 0U; i < 63U; i++) - input[i] = 0; - - // First put the parity data, 8 hex words - unsigned int offset = 96U; - for (unsigned int i = 0U; i < 8U; i++, offset += 6U) - input[i] = bin2Hex(data, offset); - - // Then the 16 hex words of data - offset = 0U; - for (unsigned int i = 8U; i < 24U; i++, offset += 6U) - input[i] = bin2Hex(data, offset); - - // Now we can call decode on the base class - int irrecoverable_errors = CReedSolomon63<4>::decode(input, output); - 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; - for (unsigned int i = 8U; i < 24U; i++, offset += 6U) - hex2Bin(output[i], data, offset); - - return true; -} - -void CRS24169::encode(unsigned char* data) -{ - assert(data != NULL); - - int input[55]; - int output[63]; - - // Fill up with zeros to complete the 55 expected hex words of data - for (unsigned int i = 0U; i < 55U; i++) - input[i] = 0; - - // Put the 16 hex words of data - unsigned int offset = 0U; - for (unsigned int i = 0U; i < 16U; i++, offset += 6U) - input[i] = bin2Hex(data, offset); - - // Now we can call encode on the base class - CReedSolomon63<4>::encode(input, output); - - // Convert it back to binary form and put it into the parity - offset = 96U; - for (unsigned int i = 0U; i < 8U; i++, offset += 6U) - hex2Bin(output[i], data, offset); -} diff --git a/RS.h b/RS.h deleted file mode 100644 index beffa32..0000000 --- a/RS.h +++ /dev/null @@ -1,491 +0,0 @@ -#ifndef REEDSOLOMON_HPP_b1405fdab6374ba2a4e65e8d45ec3d80 -#define REEDSOLOMON_HPP_b1405fdab6374ba2a4e65e8d45ec3d80 - -/** -* Code taken and adapted from www.eccpage.com/rs.c -* Credit goes to Mr Simon Rockliff. -* -* Tried before with the implementation from ITPP library but couldn't make it produce the same outputs -* expected from the P25 transmissions that I have tested. This implementation does work. -*/ - -/* This program is an encoder/decoder for Reed-Solomon codes. Encoding is in -systematic form, decoding via the Berlekamp iterative algorithm. -In the present form , the constants mm, nn, tt, and kk=nn-2tt must be -specified (the double letters are used simply to avoid clashes with -other n,k,t used in other programs into which this was incorporated!) -Also, the irreducible polynomial used to generate GF(2**mm) must also be -entered -- these can be found in Lin and Costello, and also Clark and Cain. - -The representation of the elements of GF(2**m) is either in index form, -where the number is the power of the primitive element alpha, which is -convenient for multiplication (add the powers modulo 2**m-1) or in -polynomial form, where the bits represent the coefficients of the -polynomial representation of the number, which is the most convenient form -for addition. The two forms are swapped between via lookup tables. -This leads to fairly messy looking expressions, but unfortunately, there -is no easy alternative when working with Galois arithmetic. - -The code is not written in the most elegant way, but to the best -of my knowledge, (no absolute guarantees!), it works. -However, when including it into a simulation program, you may want to do -some conversion of global variables (used here because I am lazy!) to -local variables where appropriate, and passing parameters (eg array -addresses) to the functions may be a sensible move to reduce the number -of global variables and thus decrease the chance of a bug being introduced. - -This program does not handle erasures at present, but should not be hard -to adapt to do this, as it is just an adjustment to the Berlekamp-Massey -algorithm. It also does not attempt to decode past the BCH bound -- see -Blahut "Theory and practice of error control codes" for how to do this. - -Simon Rockliff, University of Adelaide 21/9/89 - -26/6/91 Slight modifications to remove a compiler dependent bug which hadn't -previously surfaced. A few extra comments added for clarity. -Appears to all work fine, ready for posting to net! - -Notice --------- -This program may be freely modified and/or given to whoever wants it. -A condition of such distribution is that the author's contribution be -acknowledged by his name being left in the comments heading the program, -however no responsibility is accepted for any financial or other loss which -may result from some unforseen errors or malfunctioning of the program -during use. -Simon Rockliff, 26th June 1991 -*/ - -#include - -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 KK = NN - 2 * TT; - // distance = nn-kk+1 = 2*tt+1 - - int* gg; - - // 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() - { - register int i, j; - - 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 - } - - // convert gg[] to index form for quicker encoding - for (i = 0; i <= NN - KK; i++) - gg[i] = index_of[gg[i]]; - } - -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 - const int generator_polinomial[] = {1, 1, 0, 0, 0, 0, 1}; // specify irreducible polynomial coeffts - - generate_gf(generator_polinomial); - - gen_poly(); - } - - virtual ~CReedSolomon63() - { - delete[] gg; - delete[] index_of; - 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) - { - 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) { - for (j = NN - KK - 1; j > 0; j--) - if (gg[j] != -1) - 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 { - 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) - { - 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 irrecoverable_error = 0; - - for (int i = 0; i < NN; i++) - recd[i] = index_of[input[i]]; /* put recd[i] into index form (ie as powers of alpha) */ - - /* 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]]; - } - - if (syn_error) /* if errors, try and correct */ - { - /* compute the error location polynomial via the Berlekamp iterative algorithm, - following the terminology of Lin and Costello : d[u] is the 'mu'th - discrepancy, where u='mu'+1 and 'mu' (the Greek letter!) is the step number - ranging from -1 to 2*tt (see L&C), l[u] is the - 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; - u_lu[1] = 0; - u = 0; - - 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 - /* 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; - do { - j--; - if ((d[j] != -1) && (u_lu[q] < u_lu[j])) - q = j; - } while (j > 0); - }; - - /* have now found q such that d[u]!=0 and u_lu[q] is maximum */ - /* store degree of new elp polynomial */ - if (l[u] > l[q] + u - q) - l[u + 1] = l[u]; - else - l[u + 1] = l[q] + u - q; - - /* 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]; - - 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 */ - if (u < NN - KK) /* no discrepancy computed on last iteration */ - { - if (s[u + 1] != -1) - 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)); - - u++; - if (l[u] <= TT) /* can correct error */ - { - /* put elp into index form */ - for (i = 0; i <= l[u]; i++) - elp[u][i] = index_of[elp[u][i]]; - - /* 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; - loc[count] = NN - i; - count++; - }; - }; - - if (count == l[u]) /* no. roots = degree of elp hence <= tt errors */ - { - /* form polynomial z(x) */ - for (i = 1; i <= l[u]; i++) /* Z[0] = 1 always - do not need */ - { - if ((s[i] != -1) && (elp[u][i] != -1)) - z[i] = alpha_to[s[i]] ^ alpha_to[elp[u][i]]; - else if ((s[i] != -1) && (elp[u][i] == -1)) - z[i] = alpha_to[s[i]]; - else if ((s[i] == -1) && (elp[u][i] != -1)) - 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 */ - }; - - /* evaluate errors at locations given by error location numbers loc[i] */ - for (i = 0; i < NN; i++) { - err[i] = 0; - if (recd[i] != -1) /* convert recd[] to polynomial form */ - recd[i] = alpha_to[recd[i]]; - 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 = 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 { - /* no. roots != degree of elp => >tt errors and cannot solve */ - irrecoverable_error = 1; - } - - } else { - /* elp has degree >tt hence cannot solve */ - irrecoverable_error = 1; - } - - } 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 */ - recd[i] = alpha_to[recd[i]]; - else - recd[i] = 0; - } - - if (irrecoverable_error) { - for (i = 0; i < NN; i++) /* could return error flag if desired */ - if (recd[i] != -1) /* convert recd[] to polynomial form */ - recd[i] = alpha_to[recd[i]]; - else - recd[i] = 0; /* just output received codeword as is */ - } - - return irrecoverable_error; - } -}; - -class CRS362017 : public CReedSolomon63<8> -{ -public: - CRS362017(); - ~CRS362017(); - - bool decode(unsigned char* data); - - void encode(unsigned char* data); - -private: -}; - -class CRS241213 : public CReedSolomon63<6> -{ -public: - CRS241213(); - ~CRS241213(); - - bool decode(unsigned char* data); - - void encode(unsigned char* data); - -private: -}; - -class CRS24169 : public CReedSolomon63<4> -{ -public: - CRS24169(); - ~CRS24169(); - - bool decode(unsigned char* data); - - void encode(unsigned char* data); - -private: -}; - -#endif diff --git a/RS241213.cpp b/RS241213.cpp new file mode 100644 index 0000000..60fee2d --- /dev/null +++ b/RS241213.cpp @@ -0,0 +1,370 @@ +/* +* Copyright (C) 2016 by Jonathan Naylor G4KLX +* +* 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, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "RS241213.h" + +#include +#include + +const unsigned char ENCODE_MATRIX[12U][24U] = { + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 062, 044, 003, 025, 014, 016, 027, 003, 053, 004, 036, 047}, + {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 011, 012, 011, 011, 016, 064, 067, 055, 001, 076, 026, 073}, + {0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 003, 001, 005, 075, 014, 006, 020, 044, 066, 006, 070, 066}, + {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 021, 070, 027, 045, 016, 067, 023, 064, 073, 033, 044, 021}, + {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 030, 022, 003, 075, 015, 015, 033, 015, 051, 003, 053, 050}, + {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 001, 041, 027, 056, 076, 064, 021, 053, 004, 025, 001, 012}, + {0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 061, 076, 021, 055, 076, 001, 063, 035, 030, 013, 064, 070}, + {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 024, 022, 071, 056, 021, 035, 073, 042, 057, 074, 043, 076}, + {0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 072, 042, 005, 020, 043, 047, 033, 056, 001, 016, 013, 076}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 072, 014, 065, 054, 035, 025, 041, 016, 015, 040, 071, 026}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 073, 065, 036, 061, 042, 022, 017, 004, 044, 020, 025, 005}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 071, 005, 055, 003, 071, 034, 060, 011, 074, 002, 041, 050}}; + +const unsigned int rsGFexp[64] = { + 1, 2, 4, 8, 16, 32, 3, 6, 12, 24, 48, 35, 5, 10, 20, 40, + 19, 38, 15, 30, 60, 59, 53, 41, 17, 34, 7, 14, 28, 56, 51, 37, + 9, 18, 36, 11, 22, 44, 27, 54, 47, 29, 58, 55, 45, 25, 50, 39, + 13, 26, 52, 43, 21, 42, 23, 46, 31, 62, 63, 61, 57, 49, 33, 0 }; + +const unsigned int rsGFlog[64] = { + 63, 0, 1, 6, 2, 12, 7, 26, 3, 32, 13, 35, 8, 48, 27, 18, + 4, 24, 33, 16, 14, 52, 36, 54, 9, 45, 49, 38, 28, 41, 19, 56, + 5, 62, 25, 11, 34, 31, 17, 47, 15, 23, 53, 51, 37, 44, 55, 40, + 10, 61, 46, 30, 50, 22, 39, 43, 29, 60, 42, 21, 20, 59, 57, 58 }; + +const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U }; + +#define WRITE_BIT(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7]) +#define READ_BIT(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7]) + +static unsigned char bin2Hex(const unsigned char* input, unsigned int offset) +{ + unsigned char output = 0x00U; + + output |= READ_BIT(input, offset + 0U) ? 0x20U : 0x00U; + output |= READ_BIT(input, offset + 1U) ? 0x10U : 0x00U; + output |= READ_BIT(input, offset + 2U) ? 0x08U : 0x00U; + output |= READ_BIT(input, offset + 3U) ? 0x04U : 0x00U; + output |= READ_BIT(input, offset + 4U) ? 0x02U : 0x00U; + output |= READ_BIT(input, offset + 5U) ? 0x01U : 0x00U; + + return output; +} + +static void hex2Bin(unsigned char input, unsigned char* output, unsigned int offset) +{ + WRITE_BIT(output, offset + 0U, input & 0x20U); + WRITE_BIT(output, offset + 1U, input & 0x10U); + WRITE_BIT(output, offset + 2U, input & 0x08U); + WRITE_BIT(output, offset + 3U, input & 0x04U); + WRITE_BIT(output, offset + 4U, input & 0x02U); + WRITE_BIT(output, offset + 5U, input & 0x01U); +} + +CRS241213::CRS241213() +{ +} + +CRS241213::~CRS241213() +{ +} + +bool CRS241213::decode(unsigned char* data) +{ + assert(data != NULL); + + unsigned char HB[24U]; + + unsigned int offset = 0U; + for (unsigned int i = 0U; i < 24U; i++, offset += 6U) + HB[i] = bin2Hex(data, offset); + + //RS (63,63-nroots,nroots+1) decoder where nroots = number of parity bits + // rsDec(8, 39) rsDec(16, 27) rsDec(12, 39) + + const int nroots = 12; + int lambda[18];//Err+Eras Locator poly + int S[17];//syndrome poly + int b[18]; + int t[18]; + int omega[18]; + int root[17]; + int reg[18]; + int locn[17]; + + int i, j, count, r, el, SynError, DiscrR, q, DegOmega, tmp, num1, num2, den, DegLambda; + + //form the syndromes; i.e., evaluate HB(x) at roots of g(x) + for (i = 0; i <= nroots - 1; i++) { + S[i] = HB[0]; + } + + for (j = 1; j <= 62; j++) { + for (i = 0; i <= nroots - 1; i++) { + if (S[i] == 0) { + S[i] = HB[j]; + } else { + S[i] = HB[j] ^ rsGFexp[(rsGFlog[S[i]] + i + 1) % 63]; + } + } + } + + //convert syndromes to index form, checking for nonzero condition + SynError = 0; + + for (i = 0; i <= nroots - 1; i++) { + SynError = SynError | S[i]; + S[i] = rsGFlog[S[i]]; + } + + if (SynError == 0) { + //if syndrome is zero, rsData[] is a codeword and there are + //no errors to correct. So return rsData[] unmodified + count = 0; + return true; + } + + for (i = 1; i <= nroots; i++) { + lambda[i] = 0; + } + + lambda[0] = 1; + + for (i = 0; i <= nroots; i++) { + b[i] = rsGFlog[lambda[i]]; + } + + //begin Berlekamp-Massey algorithm to determine error+erasure + //locator polynomial + r = 0; + el = 0; + while (r < nroots) { //r is the step number + r = r + 1; + //compute discrepancy at the r-th step in poly-form + DiscrR = 0; + + for (i = 0; i <= r - 1; i++) { + if ((lambda[i] != 0) && (S[r - i - 1] != 63)) { + DiscrR = DiscrR ^ rsGFexp[(rsGFlog[lambda[i]] + S[r - i - 1]) % 63]; + } + } + + DiscrR = rsGFlog[DiscrR];//index form + + if (DiscrR == 63) { + //shift elements upward one step + for (i = nroots; i >= 1; i += -1) { + b[i] = b[i - 1]; + } + + b[0] = 63; + } else { + //t(x) <-- lambda(x) - DiscrR*x*b(x) + t[0] = lambda[0]; + + for (i = 0; i <= nroots - 1; i++) { + if (b[i] != 63) { + t[i + 1] = lambda[i + 1] ^ rsGFexp[(DiscrR + b[i]) % 63]; + } else { + t[i + 1] = lambda[i + 1]; + } + } + + if (2 * el <= r - 1) { + el = r - el; + //b(x) <-- inv(DiscrR) * lambda(x) + + for (i = 0; i <= nroots; i++) { + if (lambda[i]) { + b[i] = (rsGFlog[lambda[i]] - DiscrR + 63) % 63; + } else { + b[i] = 63; + } + } + } else { + //shift elements upward one step + for (i = nroots; i >= 1; i += -1) { + b[i] = b[i - 1]; + } + + b[0] = 63; + } + + for (i = 0; i <= nroots; i++) { + lambda[i] = t[i]; + } + } + } /* end while() */ + + //convert lambda to index form and compute deg(lambda(x)) + DegLambda = 0; + for (i = 0; i <= nroots; i++) { + lambda[i] = rsGFlog[lambda[i]]; + + if (lambda[i] != 63) { + DegLambda = i; + } + } + + //Find roots of the error+erasure locator polynomial by Chien search + for (i = 1; i <= nroots; i++) { + reg[i] = lambda[i]; + } + + count = 0;//number of roots of lambda(x) + + for (i = 1; i <= 63; i++) { + q = 1;//lambda[0] is always 0 + + for (j = DegLambda; j >= 1; j += -1) { + if (reg[j] != 63) { + reg[j] = (reg[j] + j) % 63; + q = q ^ rsGFexp[reg[j]]; + } + } + + if (q == 0) { //it is a root + //store root (index-form) and error location number + root[count] = i; + locn[count] = i - 1; + //if wehave max possible roots, abort search to save time + count = count + 1; + + if (count == DegLambda) { + break; + } + } + } + + if (DegLambda != count) { + //deg(lambda) unequal to number of roots => uncorrectable error detected + return false; + } + + //compute err+eras evaluator poly omega(x) + // = s(x)*lambda(x) (modulo x**nroots). in index form. Also find deg(omega). + DegOmega = 0; + for (i = 0; i <= nroots - 1; i++) { + tmp = 0; + if (DegLambda < i) { + j = DegLambda; + } else { + j = i; + } + + for ( /* j = j */; j >= 0; j += -1) { + if ((S[i - j] != 63) && (lambda[j] != 63)) { + tmp = tmp ^ rsGFexp[(S[i - j] + lambda[j]) % 63]; + } + } + + if (tmp) { + DegOmega = i; + } + + omega[i] = rsGFlog[tmp]; + } + + omega[nroots] = 63; + + //compute error values in poly-form: + // num1 = omega(inv(X(l))) + // num2 = inv(X(l))**(FCR - 1) + // den = lambda_pr(inv(X(l))) + for (j = count - 1; j >= 0; j += -1) { + num1 = 0; + + for (i = DegOmega; i >= 0; i += -1) { + if (omega[i] != 63) { + num1 = num1 ^ rsGFexp[(omega[i] + i * root[j]) % 63]; + } + } + + num2 = rsGFexp[0]; + den = 0; + + // lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] + if (DegLambda < nroots) { + i = DegLambda; + } else { + i = nroots; + } + + for (i = i & ~1; i >= 0; i += -2) { + if (lambda[i + 1] != 63) { + den = den ^ rsGFexp[(lambda[i + 1] + i * root[j]) % 63]; + } + } + + if (den == 0) { + return false; + } + + // apply error to data + if (num1 != 0) { + HB[locn[j]] = HB[locn[j]] ^ (rsGFexp[(rsGFlog[num1] + rsGFlog[num2] + 63 - rsGFlog[den]) % 63]); + } + } + + offset = 0U; + for (unsigned int i = 0U; i < 12U; i++, offset += 6U) + hex2Bin(HB[i], data, offset); + + return true; +} + +void CRS241213::encode(unsigned char* data) +{ + assert(data != NULL); + + unsigned char codeword[24U]; + + for (unsigned int i = 0U; i < 24U; i++) { + codeword[i] = 0x00U; + + unsigned int offset = 0U; + for (unsigned int j = 0U; j < 12U; j++, offset += 6U) { + unsigned char hexbit = bin2Hex(data, offset); + codeword[i] ^= gf6Mult(hexbit, ENCODE_MATRIX[j][i]); + } + } + + unsigned int offset = 0U; + for (unsigned int i = 0U; i < 24U; i++, offset += 6U) + hex2Bin(codeword[i], data, offset); +} + +// GF(2 ^ 6) multiply(for Reed - Solomon encoder) +unsigned char CRS241213::gf6Mult(unsigned char a, unsigned char b) const +{ + unsigned char p = 0x00U; + + for (unsigned int i = 0U; i < 6U; i++) { + if ((b & 0x01U) == 0x01U) + p ^= a; + + a <<= 1; + + if ((a & 0x40U) == 0x40U) + a ^= 0x43U; // primitive polynomial : x ^ 6 + x + 1 + + b >>= 1; + } + + return p; +} diff --git a/RS241213.h b/RS241213.h new file mode 100644 index 0000000..523e06a --- /dev/null +++ b/RS241213.h @@ -0,0 +1,36 @@ +/* +* Copyright (C) 2016 by Jonathan Naylor G4KLX +* +* 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, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#if !defined(RS241213_H) +#define RS241213 + +class CRS241213 +{ +public: + CRS241213(); + ~CRS241213(); + + bool decode(unsigned char* data); + + void encode(unsigned char* data); + +private: + unsigned char gf6Mult(unsigned char a, unsigned char b) const; +}; + +#endif