Add LDU1 Reed-Solomon encoding and decoding.
This commit is contained in:
parent
018b6e4dec
commit
614ee83f08
|
@ -192,8 +192,8 @@
|
|||
<ClInclude Include="P25Utils.h" />
|
||||
<ClInclude Include="QR1676.h" />
|
||||
<ClInclude Include="RingBuffer.h" />
|
||||
<ClInclude Include="RS.h" />
|
||||
<ClInclude Include="RS129.h" />
|
||||
<ClInclude Include="RS241213.h" />
|
||||
<ClInclude Include="SerialController.h" />
|
||||
<ClInclude Include="SHA256.h" />
|
||||
<ClInclude Include="StopWatch.h" />
|
||||
|
@ -253,8 +253,8 @@
|
|||
<ClCompile Include="P25NID.cpp" />
|
||||
<ClCompile Include="P25Utils.cpp" />
|
||||
<ClCompile Include="QR1676.cpp" />
|
||||
<ClCompile Include="RS.cpp" />
|
||||
<ClCompile Include="RS129.cpp" />
|
||||
<ClCompile Include="RS241213.cpp" />
|
||||
<ClCompile Include="SerialController.cpp" />
|
||||
<ClCompile Include="SHA256.cpp" />
|
||||
<ClCompile Include="StopWatch.cpp" />
|
||||
|
|
|
@ -197,10 +197,10 @@
|
|||
<ClInclude Include="DMRNetwork.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RS.h">
|
||||
<ClInclude Include="BCH.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="BCH.h">
|
||||
<ClInclude Include="RS241213.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
|
@ -370,10 +370,10 @@
|
|||
<ClCompile Include="DMRNetwork.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="RS.cpp">
|
||||
<ClCompile Include="BCH.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="BCH.cpp">
|
||||
<ClCompile Include="RS241213.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
|
|
4
Makefile
4
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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
20
P25Data.cpp
20
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);
|
||||
|
|
|
@ -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);
|
||||
|
|
289
RS.cpp
289
RS.cpp
|
@ -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 <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
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);
|
||||
}
|
491
RS.h
491
RS.h
|
@ -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 <cmath>
|
||||
|
||||
template<int TT> 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
|
370
RS241213.cpp
Normal file
370
RS241213.cpp
Normal file
|
@ -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 <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
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;
|
||||
}
|
36
RS241213.h
Normal file
36
RS241213.h
Normal file
|
@ -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
|
Loading…
Reference in a new issue