Add the P25 NID BCH encoder.

This commit is contained in:
Jonathan Naylor 2016-09-19 21:41:34 +01:00
parent 16ec0db6d8
commit 3567d83349
13 changed files with 255 additions and 16 deletions

145
BCH.cpp Normal file
View File

@ -0,0 +1,145 @@
/*
* File: bch3.c
* Title: Encoder/decoder for binary BCH codes in C (Version 3.1)
* Author: Robert Morelos-Zaragoza
* Date: August 1994
* Revised: June 13, 1997
*
* =============== Encoder/Decoder for binary BCH codes in C =================
*
* Version 1: Original program. The user provides the generator polynomial
* of the code (cumbersome!).
* Version 2: Computes the generator polynomial of the code.
* Version 3: No need to input the coefficients of a primitive polynomial of
* degree m, used to construct the Galois Field GF(2**m). The
* program now works for any binary BCH code of length such that:
* 2**(m-1) - 1 < length <= 2**m - 1
*
* Note: You may have to change the size of the arrays to make it work.
*
* The encoding and decoding methods used in this program are based on the
* book "Error Control Coding: Fundamentals and Applications", by Lin and
* Costello, Prentice Hall, 1983.
*
* Thanks to Patrick Boyle (pboyle@era.com) for his observation that 'bch2.c'
* did not work for lengths other than 2**m-1 which led to this new version.
* Portions of this program are from 'rs.c', a Reed-Solomon encoder/decoder
* in C, written by Simon Rockliff (simon@augean.ua.oz.au) on 21/9/89. The
* previous version of the BCH encoder/decoder in C, 'bch2.c', was written by
* Robert Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) on 5/19/92.
*
* NOTE:
* The author is not responsible for any malfunctioning of
* this program, nor for any damage caused by it. Please include the
* original program along with these comments in any redistribution.
*
* For more information, suggestions, or other ideas on implementing error
* correcting codes, please contact me at:
*
* Robert Morelos-Zaragoza
* 5120 Woodway, Suite 7036
* Houston, Texas 77056
*
* email: r.morelos-zaragoza@ieee.org
*
* COPYRIGHT NOTICE: This computer program is free for non-commercial purposes.
* You may implement this program for any non-commercial application. You may
* also implement this program for commercial purposes, provided that you
* obtain my written permission. Any modification of this program is covered
* by this copyright.
*
* == Copyright (c) 1994-7, Robert Morelos-Zaragoza. All rights reserved. ==
*
* m = order of the Galois field GF(2**m)
* n = 2**m - 1 = size of the multiplicative group of GF(2**m)
* length = length of the BCH code
* t = error correcting capability (max. no. of errors the code corrects)
* d = 2*t + 1 = designed min. distance = no. of consecutive roots of g(x) + 1
* k = n - deg(g(x)) = dimension (no. of information bits/codeword) of the code
* p[] = coefficients of a primitive polynomial used to generate GF(2**m)
* g[] = coefficients of the generator polynomial, g(x)
* alpha_to [] = log table of GF(2**m)
* index_of[] = antilog table of GF(2**m)
* data[] = information bits = coefficients of data polynomial, i(x)
* bb[] = coefficients of redundancy polynomial x^(length-k) i(x) modulo g(x)
* numerr = number of errors
* errpos[] = error positions
* recd[] = coefficients of the received polynomial
* decerror = number of decoding errors (in _message_ positions)
*
*/
#include "BCH.h"
#include "Utils.h"
#include "Log.h"
#include <cmath>
#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])
const int length = 63;
const int k = 16;
const int g[] = {1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1,
1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1};
CBCH::CBCH()
{
}
CBCH::~CBCH()
{
}
void CBCH::encode(const int* data, int* bb)
/*
* Compute redundacy bb[], the coefficients of b(x). The redundancy
* polynomial b(x) is the remainder after dividing x^(length-k)*data(x)
* by the generator polynomial g(x).
*/
{
for (int i = 0; i < length - k; i++)
bb[i] = 0;
for (int i = k - 1; i >= 0; i--) {
int feedback = data[i] ^ bb[length - k - 1];
if (feedback != 0) {
for (int j = length - k - 1; j > 0; j--)
if (g[j] != 0)
bb[j] = bb[j - 1] ^ feedback;
else
bb[j] = bb[j - 1];
bb[0] = g[0] && feedback;
} else {
for (int j = length - k - 1; j > 0; j--)
bb[j] = bb[j - 1];
bb[0] = 0;
}
}
}
void CBCH::encode(unsigned char* nid)
{
assert(nid != NULL);
CUtils::dump(1U, "data", nid, 2U);
int data[16];
for (int i = 0; i < 16; i++)
data[i] = READ_BIT(nid, i) ? 1 : 0;
int bb[63];
encode(data, bb);
for (int i = 0; i < (length - k); i++) {
bool b = bb[i] == 1;
WRITE_BIT(nid, i + 16U, b);
}
CUtils::dump(1U, "out", nid, 8U);
}

33
BCH.h Normal file
View File

@ -0,0 +1,33 @@
/*
* 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(BCH_H)
#define BCH_H
class CBCH {
public:
CBCH();
~CBCH();
void encode(unsigned char* data);
private:
void encode(const int* data, int* bb);
};
#endif

View File

@ -147,6 +147,7 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="AMBEFEC.h" />
<ClInclude Include="BCH.h" />
<ClInclude Include="BPTC19696.h" />
<ClInclude Include="Conf.h" />
<ClInclude Include="CRC.h" />
@ -212,6 +213,7 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="AMBEFEC.cpp" />
<ClCompile Include="BCH.cpp" />
<ClCompile Include="BPTC19696.cpp" />
<ClCompile Include="Conf.cpp" />
<ClCompile Include="CRC.cpp" />

View File

@ -200,6 +200,9 @@
<ClInclude Include="RS.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="BCH.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="BPTC19696.cpp">
@ -370,5 +373,8 @@
<ClCompile Include="RS.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="BCH.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -7,7 +7,7 @@ LIBS = -lpthread
LDFLAGS = -g
OBJECTS = \
AMBEFEC.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 \
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 \

View File

@ -7,7 +7,7 @@ LIBS = -lwiringPi -lwiringPiDev -lpthread
LDFLAGS = -g -L/usr/local/lib
OBJECTS = \
AMBEFEC.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 \
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 \

View File

@ -7,7 +7,7 @@ LIBS = -lwiringPi -lwiringPiDev -lpthread
LDFLAGS = -g -L/usr/local/lib
OBJECTS = \
AMBEFEC.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 \
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 \

View File

@ -7,7 +7,7 @@ LIBS = -lArduiPi_OLED -lpthread
LDFLAGS = -g -L/usr/local/lib
OBJECTS = \
AMBEFEC.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 \
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 \

View File

@ -7,7 +7,7 @@ LIBS = -lwiringPi -lwiringPiDev -lpthread
LDFLAGS = -g -L/usr/local/lib
OBJECTS = \
AMBEFEC.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 \
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 \

View File

@ -7,7 +7,7 @@ LIBS = -lpthread -lsocket
LDFLAGS = -g
OBJECTS = \
AMBEFEC.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 \
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 \

View File

@ -54,7 +54,7 @@ m_netFrames(0U),
m_netBits(0U),
m_netErrs(0U),
m_netLost(0U),
m_nid(),
m_nid(nac),
m_audio(),
m_rfData(),
m_netData()
@ -82,6 +82,7 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len)
LogMessage("P25, transmission lost, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits));
if (m_netState == RS_NET_IDLE)
m_display->clearP25();
writeNetwork(data + 2U, P25_DUID_TERM);
m_rfState = RS_RF_LISTENING;
m_rfTimeout.stop();
m_rfData.reset();

View File

@ -19,21 +19,68 @@
#include "P25NID.h"
#include "P25Defines.h"
#include "P25Utils.h"
#include "BCH.h"
#include <cstdio>
#include <cassert>
CP25NID::CP25NID() :
CP25NID::CP25NID(unsigned int nac) :
m_duid(0U),
m_nac(0U)
m_nac(0U),
m_hdr(NULL),
m_ldu1(NULL),
m_ldu2(NULL),
m_termlc(NULL),
m_term(NULL)
{
CBCH bch;
m_hdr = new unsigned char[P25_NID_LENGTH_BYTES];
m_hdr[0U] = (nac >> 4) & 0xFFU;
m_hdr[1U] = (nac << 4) & 0xF0U;
m_hdr[1U] |= P25_DUID_HEADER;
bch.encode(m_hdr);
m_hdr[7U] &= 0xFEU; // Clear the parity bit
m_ldu1 = new unsigned char[P25_NID_LENGTH_BYTES];
m_ldu1[0U] = (nac >> 4) & 0xFFU;
m_ldu1[1U] = (nac << 4) & 0xF0U;
m_ldu1[1U] |= P25_DUID_LDU1;
bch.encode(m_ldu1);
m_ldu1[7U] |= 0x01U; // Set the parity bit
m_ldu2 = new unsigned char[P25_NID_LENGTH_BYTES];
m_ldu2[0U] = (nac >> 4) & 0xFFU;
m_ldu2[1U] = (nac << 4) & 0xF0U;
m_ldu2[1U] |= P25_DUID_LDU2;
bch.encode(m_ldu2);
m_ldu2[7U] |= 0x01U; // Set the parity bit
m_termlc = new unsigned char[P25_NID_LENGTH_BYTES];
m_termlc[0U] = (nac >> 4) & 0xFFU;
m_termlc[1U] = (nac << 4) & 0xF0U;
m_termlc[1U] |= P25_DUID_TERM_LC;
bch.encode(m_termlc);
m_termlc[7U] &= 0xFEU; // Clear the parity bit
m_term = new unsigned char[P25_NID_LENGTH_BYTES];
m_term[0U] = (nac >> 4) & 0xFFU;
m_term[1U] = (nac << 4) & 0xF0U;
m_term[1U] |= P25_DUID_TERM;
bch.encode(m_term);
m_term[7U] &= 0xFEU; // Clear the parity bit
}
CP25NID::~CP25NID()
{
delete[] m_hdr;
delete[] m_ldu1;
delete[] m_ldu2;
delete[] m_termlc;
delete[] m_term;
}
void CP25NID::process(unsigned char* data)
bool CP25NID::process(unsigned char* data)
{
assert(data != NULL);
@ -41,14 +88,14 @@ void CP25NID::process(unsigned char* data)
CP25Utils::decode(data, nid, 48U, 114U);
// XXX Process FEC here
m_duid = nid[1U] & 0x0FU;
m_nac = (nid[0U] << 4) & 0xFF0U;
m_nac |= (nid[1U] >> 4) & 0x00FU;
CP25Utils::encode(nid, data, 48U, 114U);
return true;
}
unsigned char CP25NID::getDUID() const

View File

@ -21,17 +21,22 @@
class CP25NID {
public:
CP25NID();
CP25NID(unsigned int nac);
~CP25NID();
void process(unsigned char* data);
bool process(unsigned char* data);
unsigned char getDUID() const;
unsigned int getNAC() const;
private:
unsigned char m_duid;
unsigned int m_nac;
unsigned char m_duid;
unsigned int m_nac;
unsigned char* m_hdr;
unsigned char* m_ldu1;
unsigned char* m_ldu2;
unsigned char* m_termlc;
unsigned char* m_term;
};
#endif