diff --git a/BCH.cpp b/BCH.cpp new file mode 100644 index 0000000..4769689 --- /dev/null +++ b/BCH.cpp @@ -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 +#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]) + +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); +} diff --git a/BCH.h b/BCH.h new file mode 100644 index 0000000..fa1265d --- /dev/null +++ b/BCH.h @@ -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 diff --git a/MMDVMHost.vcxproj b/MMDVMHost.vcxproj index 766a80e..ff38eb5 100644 --- a/MMDVMHost.vcxproj +++ b/MMDVMHost.vcxproj @@ -147,6 +147,7 @@ + @@ -212,6 +213,7 @@ + diff --git a/MMDVMHost.vcxproj.filters b/MMDVMHost.vcxproj.filters index 480dfb2..59775be 100644 --- a/MMDVMHost.vcxproj.filters +++ b/MMDVMHost.vcxproj.filters @@ -200,6 +200,9 @@ Header Files + + Header Files + @@ -370,5 +373,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/Makefile b/Makefile index 2e8f0f4..6cbcfbc 100644 --- a/Makefile +++ b/Makefile @@ -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 \ diff --git a/Makefile.Pi.Adafruit b/Makefile.Pi.Adafruit index 8af888f..52ee6fd 100644 --- a/Makefile.Pi.Adafruit +++ b/Makefile.Pi.Adafruit @@ -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 \ diff --git a/Makefile.Pi.HD44780 b/Makefile.Pi.HD44780 index fbcd68e..84e0598 100644 --- a/Makefile.Pi.HD44780 +++ b/Makefile.Pi.HD44780 @@ -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 \ diff --git a/Makefile.Pi.OLED b/Makefile.Pi.OLED index 0d40a9c..762390c 100644 --- a/Makefile.Pi.OLED +++ b/Makefile.Pi.OLED @@ -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 \ diff --git a/Makefile.Pi.PCF8574 b/Makefile.Pi.PCF8574 index 9cf610e..7bf174c 100644 --- a/Makefile.Pi.PCF8574 +++ b/Makefile.Pi.PCF8574 @@ -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 \ diff --git a/Makefile.Solaris b/Makefile.Solaris index b32468e..d4b43c0 100644 --- a/Makefile.Solaris +++ b/Makefile.Solaris @@ -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 \ diff --git a/P25Control.cpp b/P25Control.cpp index f34fff9..e1606f0 100644 --- a/P25Control.cpp +++ b/P25Control.cpp @@ -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(); diff --git a/P25NID.cpp b/P25NID.cpp index 24ec959..d29eef2 100644 --- a/P25NID.cpp +++ b/P25NID.cpp @@ -19,21 +19,68 @@ #include "P25NID.h" #include "P25Defines.h" #include "P25Utils.h" +#include "BCH.h" #include #include -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 diff --git a/P25NID.h b/P25NID.h index 414c0b5..fee5a4a 100644 --- a/P25NID.h +++ b/P25NID.h @@ -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