diff --git a/BPTC19696.cpp b/BPTC19696.cpp new file mode 100644 index 0000000..289005a --- /dev/null +++ b/BPTC19696.cpp @@ -0,0 +1,347 @@ +/* + * Copyright (C) 2012 by Ian Wraith + * Copyright (C) 2015 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 "BPTC19696.h" + +#include "Hamming.h" +#include "Utils.h" + +#include +#include +#include + +CBPTC19696::CBPTC19696() : +m_rawData(NULL), +m_deInterData(NULL) +{ + m_rawData = new bool[196]; + m_deInterData = new bool[196]; +} + +CBPTC19696::~CBPTC19696() +{ + delete[] m_rawData; + delete[] m_deInterData; +} + +// The main decode function +void CBPTC19696::decode(const unsigned char* in, unsigned char* out) +{ + assert(in != NULL); + assert(out != NULL); + + // Get the raw binary + decodeExtractBinary(in); + + // Deinterleave + decodeDeInterleave(); + + // Error check + decodeErrorCheck(); + + // Extract Data + decodeExtractData(out); +} + +// The main encode function +void CBPTC19696::encode(const unsigned char* in, unsigned char* out) +{ + assert(in != NULL); + assert(out != NULL); + + // Extract Data + encodeExtractData(in); + + // Error check + encodeErrorCheck(); + + // Deinterleave + encodeInterleave(); + + // Get the raw binary + encodeExtractBinary(out); +} + +void CBPTC19696::decodeExtractBinary(const unsigned char* in) +{ + // First block + CUtils::byteToBitsBE(in[0U], m_rawData + 0U); + CUtils::byteToBitsBE(in[1U], m_rawData + 8U); + CUtils::byteToBitsBE(in[2U], m_rawData + 16U); + CUtils::byteToBitsBE(in[3U], m_rawData + 24U); + CUtils::byteToBitsBE(in[4U], m_rawData + 32U); + CUtils::byteToBitsBE(in[5U], m_rawData + 40U); + CUtils::byteToBitsBE(in[6U], m_rawData + 48U); + CUtils::byteToBitsBE(in[7U], m_rawData + 56U); + CUtils::byteToBitsBE(in[8U], m_rawData + 64U); + CUtils::byteToBitsBE(in[9U], m_rawData + 72U); + CUtils::byteToBitsBE(in[10U], m_rawData + 80U); + CUtils::byteToBitsBE(in[11U], m_rawData + 88U); + CUtils::byteToBitsBE(in[12U], m_rawData + 96U); + + // Handle the two bits + bool bits[8U]; + CUtils::byteToBitsBE(in[20U], bits); + m_rawData[98U] = bits[6U]; + m_rawData[99U] = bits[7U]; + + // Second block + CUtils::byteToBitsBE(in[21U], m_rawData + 100U); + CUtils::byteToBitsBE(in[22U], m_rawData + 108U); + CUtils::byteToBitsBE(in[23U], m_rawData + 116U); + CUtils::byteToBitsBE(in[24U], m_rawData + 124U); + CUtils::byteToBitsBE(in[25U], m_rawData + 132U); + CUtils::byteToBitsBE(in[26U], m_rawData + 140U); + CUtils::byteToBitsBE(in[27U], m_rawData + 148U); + CUtils::byteToBitsBE(in[28U], m_rawData + 156U); + CUtils::byteToBitsBE(in[29U], m_rawData + 164U); + CUtils::byteToBitsBE(in[30U], m_rawData + 172U); + CUtils::byteToBitsBE(in[31U], m_rawData + 180U); + CUtils::byteToBitsBE(in[32U], m_rawData + 188U); +} + +// Deinterleave the raw data +void CBPTC19696::decodeDeInterleave() +{ + for (unsigned int i = 0U; i < 196U; i++) + m_deInterData[i] = false; + + // The first bit is R(3) which is not used so can be ignored + for (unsigned int a = 0U; a < 196U; a++) { + // Calculate the interleave sequence + unsigned int interleaveSequence = (a * 181U) % 196U; + // Shuffle the data + m_deInterData[a] = m_rawData[interleaveSequence]; + } +} + +// Check each row with a Hamming (15,11,3) code and each column with a Hamming (13,9,3) code +void CBPTC19696::decodeErrorCheck() +{ + bool fixing; + unsigned int count = 0U; + do { + fixing = false; + + // Run through each of the 15 columns + bool col[13U]; + for (unsigned int c = 0U; c < 15U; c++) { + unsigned int pos = c + 1U; + for (unsigned int a = 0U; a < 13U; a++) { + col[a] = m_deInterData[pos]; + pos = pos + 15U; + } + + if (CHamming::decode1393(col)) { + unsigned int pos = c + 1U; + for (unsigned int a = 0U; a < 13U; a++) { + m_deInterData[pos] = col[a]; + pos = pos + 15U; + } + + fixing = true; + } + } + + // Run through each of the 9 rows containing data + for (unsigned int r = 0U; r < 9U; r++) { + unsigned int pos = (r * 15U) + 1U; + if (CHamming::decode15113_2(m_deInterData + pos)) + fixing = true; + } + + count++; + } while (fixing && count < 5U); +} + +// Extract the 96 bits of payload +void CBPTC19696::decodeExtractData(unsigned char* data) const +{ + bool bData[96U]; + unsigned int pos = 0U; + for (unsigned int a = 4U; a <= 11U; a++, pos++) + bData[pos] = m_deInterData[a]; + + for (unsigned int a = 16U; a <= 26U; a++, pos++) + bData[pos] = m_deInterData[a]; + + for (unsigned int a = 31U; a <= 41U; a++, pos++) + bData[pos] = m_deInterData[a]; + + for (unsigned int a = 46U; a <= 56U; a++, pos++) + bData[pos] = m_deInterData[a]; + + for (unsigned int a = 61U; a <= 71U; a++, pos++) + bData[pos] = m_deInterData[a]; + + for (unsigned int a = 76U; a <= 86U; a++, pos++) + bData[pos] = m_deInterData[a]; + + for (unsigned int a = 91U; a <= 101U; a++, pos++) + bData[pos] = m_deInterData[a]; + + for (unsigned int a = 106U; a <= 116U; a++, pos++) + bData[pos] = m_deInterData[a]; + + for (unsigned int a = 121U; a <= 131U; a++, pos++) + bData[pos] = m_deInterData[a]; + + CUtils::bitsToByteBE(bData + 0U, data[0U]); + CUtils::bitsToByteBE(bData + 8U, data[1U]); + CUtils::bitsToByteBE(bData + 16U, data[2U]); + CUtils::bitsToByteBE(bData + 24U, data[3U]); + CUtils::bitsToByteBE(bData + 32U, data[4U]); + CUtils::bitsToByteBE(bData + 40U, data[5U]); + CUtils::bitsToByteBE(bData + 48U, data[6U]); + CUtils::bitsToByteBE(bData + 56U, data[7U]); + CUtils::bitsToByteBE(bData + 64U, data[8U]); + CUtils::bitsToByteBE(bData + 72U, data[9U]); + CUtils::bitsToByteBE(bData + 80U, data[10U]); + CUtils::bitsToByteBE(bData + 88U, data[11U]); +} + +// Extract the 96 bits of payload +void CBPTC19696::encodeExtractData(const unsigned char* in) const +{ + bool bData[96U]; + CUtils::byteToBitsBE(in[0U], bData + 0U); + CUtils::byteToBitsBE(in[1U], bData + 8U); + CUtils::byteToBitsBE(in[2U], bData + 16U); + CUtils::byteToBitsBE(in[3U], bData + 24U); + CUtils::byteToBitsBE(in[4U], bData + 32U); + CUtils::byteToBitsBE(in[5U], bData + 40U); + CUtils::byteToBitsBE(in[6U], bData + 48U); + CUtils::byteToBitsBE(in[7U], bData + 56U); + CUtils::byteToBitsBE(in[8U], bData + 64U); + CUtils::byteToBitsBE(in[9U], bData + 72U); + CUtils::byteToBitsBE(in[10U], bData + 80U); + CUtils::byteToBitsBE(in[11U], bData + 88U); + + for (unsigned int i = 0U; i < 196U; i++) + m_deInterData[i] = false; + + unsigned int pos = 0U; + for (unsigned int a = 4U; a <= 11U; a++, pos++) + m_deInterData[a] = bData[pos]; + + for (unsigned int a = 16U; a <= 26U; a++, pos++) + m_deInterData[a] = bData[pos]; + + for (unsigned int a = 31U; a <= 41U; a++, pos++) + m_deInterData[a] = bData[pos]; + + for (unsigned int a = 46U; a <= 56U; a++, pos++) + m_deInterData[a] = bData[pos]; + + for (unsigned int a = 61U; a <= 71U; a++, pos++) + m_deInterData[a] = bData[pos]; + + for (unsigned int a = 76U; a <= 86U; a++, pos++) + m_deInterData[a] = bData[pos]; + + for (unsigned int a = 91U; a <= 101U; a++, pos++) + m_deInterData[a] = bData[pos]; + + for (unsigned int a = 106U; a <= 116U; a++, pos++) + m_deInterData[a] = bData[pos]; + + for (unsigned int a = 121U; a <= 131U; a++, pos++) + m_deInterData[a] = bData[pos]; +} + +// Check each row with a Hamming (15,11,3) code and each column with a Hamming (13,9,3) code +void CBPTC19696::encodeErrorCheck() +{ + + // Run through each of the 9 rows containing data + for (unsigned int r = 0U; r < 9U; r++) { + unsigned int pos = (r * 15U) + 1U; + CHamming::encode15113_2(m_deInterData + pos); + } + + // Run through each of the 15 columns + bool col[13U]; + for (unsigned int c = 0U; c < 15U; c++) { + unsigned int pos = c + 1U; + for (unsigned int a = 0U; a < 13U; a++) { + col[a] = m_deInterData[pos]; + pos = pos + 15U; + } + + CHamming::encode1393(col); + + pos = c + 1U; + for (unsigned int a = 0U; a < 13U; a++) { + m_deInterData[pos] = col[a]; + pos = pos + 15U; + } + } +} + +// Interleave the raw data +void CBPTC19696::encodeInterleave() +{ + for (unsigned int i = 0U; i < 196U; i++) + m_rawData[i] = false; + + // The first bit is R(3) which is not used so can be ignored + for (unsigned int a = 0U; a < 196U; a++) { + // Calculate the interleave sequence + unsigned int interleaveSequence = (a * 181U) % 196U; + // Unshuffle the data + m_rawData[interleaveSequence] = m_deInterData[a]; + } +} + +void CBPTC19696::encodeExtractBinary(unsigned char* data) +{ + // First block + CUtils::bitsToByteBE(m_rawData + 0U, data[0U]); + CUtils::bitsToByteBE(m_rawData + 8U, data[1U]); + CUtils::bitsToByteBE(m_rawData + 16U, data[2U]); + CUtils::bitsToByteBE(m_rawData + 24U, data[3U]); + CUtils::bitsToByteBE(m_rawData + 32U, data[4U]); + CUtils::bitsToByteBE(m_rawData + 40U, data[5U]); + CUtils::bitsToByteBE(m_rawData + 48U, data[6U]); + CUtils::bitsToByteBE(m_rawData + 56U, data[7U]); + CUtils::bitsToByteBE(m_rawData + 64U, data[8U]); + CUtils::bitsToByteBE(m_rawData + 72U, data[9U]); + CUtils::bitsToByteBE(m_rawData + 80U, data[10U]); + CUtils::bitsToByteBE(m_rawData + 88U, data[11U]); + + // Handle the two bits + unsigned char byte; + CUtils::bitsToByteBE(m_rawData + 96U, byte); + data[12U] = (data[12U] & 0x3FU) | ((byte >> 0) & 0xC0U); + data[20U] = (data[20U] & 0xFCU) | ((byte >> 4) & 0x03U); + + // Second block + CUtils::bitsToByteBE(m_rawData + 100U, data[21U]); + CUtils::bitsToByteBE(m_rawData + 108U, data[22U]); + CUtils::bitsToByteBE(m_rawData + 116U, data[23U]); + CUtils::bitsToByteBE(m_rawData + 124U, data[24U]); + CUtils::bitsToByteBE(m_rawData + 132U, data[25U]); + CUtils::bitsToByteBE(m_rawData + 140U, data[26U]); + CUtils::bitsToByteBE(m_rawData + 148U, data[27U]); + CUtils::bitsToByteBE(m_rawData + 156U, data[28U]); + CUtils::bitsToByteBE(m_rawData + 164U, data[29U]); + CUtils::bitsToByteBE(m_rawData + 172U, data[30U]); + CUtils::bitsToByteBE(m_rawData + 180U, data[31U]); + CUtils::bitsToByteBE(m_rawData + 188U, data[32U]); +} diff --git a/BPTC19696.h b/BPTC19696.h new file mode 100644 index 0000000..0a40a78 --- /dev/null +++ b/BPTC19696.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2015 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(BPTC19696_H) +#define BPTC19696_H + +class CBPTC19696 +{ +public: + CBPTC19696(); + ~CBPTC19696(); + + void decode(const unsigned char* in, unsigned char* out); + + void encode(const unsigned char* in, unsigned char* out); + +private: + bool* m_rawData; + bool* m_deInterData; + + void decodeExtractBinary(const unsigned char* in); + void decodeErrorCheck(); + void decodeDeInterleave(); + void decodeExtractData(unsigned char* data) const; + + void encodeExtractData(const unsigned char* in) const; + void encodeInterleave(); + void encodeErrorCheck(); + void encodeExtractBinary(unsigned char* data); +}; + +#endif diff --git a/CRC.cpp b/CRC.cpp new file mode 100644 index 0000000..c99ca6c --- /dev/null +++ b/CRC.cpp @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2015,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 "CRC.h" + +#include "Utils.h" +#include "Log.h" + +#include +#include +#include +#include + +const uint8_t CRC8_TABLE[] = { + 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, + 0x24, 0x23, 0x2A, 0x2D, 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, + 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, 0xE0, 0xE7, 0xEE, 0xE9, + 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, + 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, + 0xB4, 0xB3, 0xBA, 0xBD, 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, + 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, 0xB7, 0xB0, 0xB9, 0xBE, + 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, + 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, + 0x03, 0x04, 0x0D, 0x0A, 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, + 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, 0x89, 0x8E, 0x87, 0x80, + 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, + 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, + 0xDD, 0xDA, 0xD3, 0xD4, 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, + 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, 0x19, 0x1E, 0x17, 0x10, + 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, + 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, + 0x6A, 0x6D, 0x64, 0x63, 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, + 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, 0xAE, 0xA9, 0xA0, 0xA7, + 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, + 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, + 0xFA, 0xFD, 0xF4, 0xF3, 0x01 }; + +const uint16_t CCITT16_TABLE1[] = { + 0x0000U, 0x1189U, 0x2312U, 0x329bU, 0x4624U, 0x57adU, 0x6536U, 0x74bfU, + 0x8c48U, 0x9dc1U, 0xaf5aU, 0xbed3U, 0xca6cU, 0xdbe5U, 0xe97eU, 0xf8f7U, + 0x1081U, 0x0108U, 0x3393U, 0x221aU, 0x56a5U, 0x472cU, 0x75b7U, 0x643eU, + 0x9cc9U, 0x8d40U, 0xbfdbU, 0xae52U, 0xdaedU, 0xcb64U, 0xf9ffU, 0xe876U, + 0x2102U, 0x308bU, 0x0210U, 0x1399U, 0x6726U, 0x76afU, 0x4434U, 0x55bdU, + 0xad4aU, 0xbcc3U, 0x8e58U, 0x9fd1U, 0xeb6eU, 0xfae7U, 0xc87cU, 0xd9f5U, + 0x3183U, 0x200aU, 0x1291U, 0x0318U, 0x77a7U, 0x662eU, 0x54b5U, 0x453cU, + 0xbdcbU, 0xac42U, 0x9ed9U, 0x8f50U, 0xfbefU, 0xea66U, 0xd8fdU, 0xc974U, + 0x4204U, 0x538dU, 0x6116U, 0x709fU, 0x0420U, 0x15a9U, 0x2732U, 0x36bbU, + 0xce4cU, 0xdfc5U, 0xed5eU, 0xfcd7U, 0x8868U, 0x99e1U, 0xab7aU, 0xbaf3U, + 0x5285U, 0x430cU, 0x7197U, 0x601eU, 0x14a1U, 0x0528U, 0x37b3U, 0x263aU, + 0xdecdU, 0xcf44U, 0xfddfU, 0xec56U, 0x98e9U, 0x8960U, 0xbbfbU, 0xaa72U, + 0x6306U, 0x728fU, 0x4014U, 0x519dU, 0x2522U, 0x34abU, 0x0630U, 0x17b9U, + 0xef4eU, 0xfec7U, 0xcc5cU, 0xddd5U, 0xa96aU, 0xb8e3U, 0x8a78U, 0x9bf1U, + 0x7387U, 0x620eU, 0x5095U, 0x411cU, 0x35a3U, 0x242aU, 0x16b1U, 0x0738U, + 0xffcfU, 0xee46U, 0xdcddU, 0xcd54U, 0xb9ebU, 0xa862U, 0x9af9U, 0x8b70U, + 0x8408U, 0x9581U, 0xa71aU, 0xb693U, 0xc22cU, 0xd3a5U, 0xe13eU, 0xf0b7U, + 0x0840U, 0x19c9U, 0x2b52U, 0x3adbU, 0x4e64U, 0x5fedU, 0x6d76U, 0x7cffU, + 0x9489U, 0x8500U, 0xb79bU, 0xa612U, 0xd2adU, 0xc324U, 0xf1bfU, 0xe036U, + 0x18c1U, 0x0948U, 0x3bd3U, 0x2a5aU, 0x5ee5U, 0x4f6cU, 0x7df7U, 0x6c7eU, + 0xa50aU, 0xb483U, 0x8618U, 0x9791U, 0xe32eU, 0xf2a7U, 0xc03cU, 0xd1b5U, + 0x2942U, 0x38cbU, 0x0a50U, 0x1bd9U, 0x6f66U, 0x7eefU, 0x4c74U, 0x5dfdU, + 0xb58bU, 0xa402U, 0x9699U, 0x8710U, 0xf3afU, 0xe226U, 0xd0bdU, 0xc134U, + 0x39c3U, 0x284aU, 0x1ad1U, 0x0b58U, 0x7fe7U, 0x6e6eU, 0x5cf5U, 0x4d7cU, + 0xc60cU, 0xd785U, 0xe51eU, 0xf497U, 0x8028U, 0x91a1U, 0xa33aU, 0xb2b3U, + 0x4a44U, 0x5bcdU, 0x6956U, 0x78dfU, 0x0c60U, 0x1de9U, 0x2f72U, 0x3efbU, + 0xd68dU, 0xc704U, 0xf59fU, 0xe416U, 0x90a9U, 0x8120U, 0xb3bbU, 0xa232U, + 0x5ac5U, 0x4b4cU, 0x79d7U, 0x685eU, 0x1ce1U, 0x0d68U, 0x3ff3U, 0x2e7aU, + 0xe70eU, 0xf687U, 0xc41cU, 0xd595U, 0xa12aU, 0xb0a3U, 0x8238U, 0x93b1U, + 0x6b46U, 0x7acfU, 0x4854U, 0x59ddU, 0x2d62U, 0x3cebU, 0x0e70U, 0x1ff9U, + 0xf78fU, 0xe606U, 0xd49dU, 0xc514U, 0xb1abU, 0xa022U, 0x92b9U, 0x8330U, + 0x7bc7U, 0x6a4eU, 0x58d5U, 0x495cU, 0x3de3U, 0x2c6aU, 0x1ef1U, 0x0f78U }; + +const uint16_t CCITT16_TABLE2[] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, + 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, + 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, + 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, + 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, + 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, + 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, + 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, + 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, + 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, + 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, + 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, + 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, + 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, + 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, + 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, + 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, + 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, + 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, + 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, + 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, + 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, + 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 }; + + +bool CCRC::checkFiveBit(bool* in, unsigned int tcrc) +{ + assert(in != NULL); + + unsigned int crc; + encodeFiveBit(in, crc); + + return crc == tcrc; +} + +void CCRC::encodeFiveBit(const bool* in, unsigned int& tcrc) +{ + assert(in != NULL); + + unsigned short total = 0U; + for (unsigned int i = 0U; i < 72U; i += 8U) { + unsigned char c; + CUtils::bitsToByteBE(in + i, c); + total += c; + } + + total %= 31U; + + tcrc = total; +} + +void CCRC::addCCITT162(unsigned char *in, unsigned int length) +{ + assert(in != NULL); + assert(length > 2U); + + union { + uint16_t crc16; + uint8_t crc8[2U]; + }; + + crc16 = 0U; + + for (unsigned i = 0U; i < (length - 2U); i++) + crc16 = (uint16_t(crc8[0U]) << 8) ^ CCITT16_TABLE2[crc8[1U] ^ in[i]]; + + crc16 = ~crc16; + + in[length - 1U] = crc8[0U]; + in[length - 2U] = crc8[1U]; +} + +bool CCRC::checkCCITT162(const unsigned char *in, unsigned int length) +{ + assert(in != NULL); + assert(length > 2U); + + union { + uint16_t crc16; + uint8_t crc8[2U]; + }; + + crc16 = 0U; + + for (unsigned i = 0U; i < (length - 2U); i++) + crc16 = (uint16_t(crc8[0U]) << 8) ^ CCITT16_TABLE2[crc8[1U] ^ in[i]]; + + crc16 = ~crc16; + + return crc8[0U] == in[length - 1U] && crc8[1U] == in[length - 2U]; +} + +void CCRC::addCCITT161(unsigned char *in, unsigned int length) +{ + assert(in != NULL); + assert(length > 2U); + + union { + uint16_t crc16; + uint8_t crc8[2U]; + }; + + crc16 = 0xFFFFU; + + for (unsigned int i = 0U; i < (length - 2U); i++) + crc16 = uint16_t(crc8[1U]) ^ CCITT16_TABLE1[crc8[0U] ^ in[i]]; + + crc16 = ~crc16; + + in[length - 2U] = crc8[0U]; + in[length - 1U] = crc8[1U]; +} + +bool CCRC::checkCCITT161(const unsigned char *in, unsigned int length) +{ + assert(in != NULL); + assert(length > 2U); + + union { + uint16_t crc16; + uint8_t crc8[2U]; + }; + + crc16 = 0xFFFFU; + + for (unsigned int i = 0U; i < (length - 2U); i++) + crc16 = uint16_t(crc8[1U]) ^ CCITT16_TABLE1[crc8[0U] ^ in[i]]; + + crc16 = ~crc16; + + return crc8[0U] == in[length - 2U] && crc8[1U] == in[length - 1U]; +} + +unsigned char CCRC::crc8(const unsigned char *in, unsigned int length) +{ + assert(in != NULL); + + uint8_t crc = 0U; + + for (unsigned int i = 0U; i < length; i++) + crc = CRC8_TABLE[crc ^ in[i]]; + + return crc; +} diff --git a/CRC.h b/CRC.h new file mode 100644 index 0000000..e80c3f6 --- /dev/null +++ b/CRC.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2015,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(CRC_H) +#define CRC_H + +class CCRC +{ +public: + static bool checkFiveBit(bool* in, unsigned int tcrc); + static void encodeFiveBit(const bool* in, unsigned int& tcrc); + + static void addCCITT161(unsigned char* in, unsigned int length); + static void addCCITT162(unsigned char* in, unsigned int length); + + static bool checkCCITT161(const unsigned char* in, unsigned int length); + static bool checkCCITT162(const unsigned char* in, unsigned int length); + + static unsigned char crc8(const unsigned char* in, unsigned int length); +}; + +#endif diff --git a/Conf.cpp b/Conf.cpp index b5cc8d0..4d2825c 100644 --- a/Conf.cpp +++ b/Conf.cpp @@ -38,6 +38,7 @@ CConf::CConf(const std::string& file) : m_file(file), m_daemon(false), m_xlxSlot(2U), +m_xlxTG(9U), m_rptAddress("127.0.0.1"), m_rptPort(62032U), m_localAddress("127.0.0.1"), @@ -109,6 +110,8 @@ bool CConf::read() m_daemon = ::atoi(value) == 1; else if (::strcmp(key, "XLSSlot") == 0) m_xlxSlot = (unsigned int)::atoi(value); + else if (::strcmp(key, "XLXTG") == 0) + m_xlxTG = (unsigned int)::atoi(value); else if (::strcmp(key, "Timeout") == 0) m_timeout = (unsigned int)::atoi(value); else if (::strcmp(key, "RptAddress") == 0) @@ -122,14 +125,14 @@ bool CConf::read() else if (::strcmp(key, "Debug") == 0) m_debug = ::atoi(value) == 1; } else if (section == SECTION_LOG) { - if (::strcmp(key, "FilePath") == 0) - m_logFilePath = value; - else if (::strcmp(key, "FileRoot") == 0) - m_logFileRoot = value; - else if (::strcmp(key, "FileLevel") == 0) - m_logFileLevel = (unsigned int)::atoi(value); - else if (::strcmp(key, "DisplayLevel") == 0) - m_logDisplayLevel = (unsigned int)::atoi(value); + if (::strcmp(key, "FilePath") == 0) + m_logFilePath = value; + else if (::strcmp(key, "FileRoot") == 0) + m_logFileRoot = value; + else if (::strcmp(key, "FileLevel") == 0) + m_logFileLevel = (unsigned int)::atoi(value); + else if (::strcmp(key, "DisplayLevel") == 0) + m_logDisplayLevel = (unsigned int)::atoi(value); } else if (section == SECTION_XLX_NETWORK) { if (::strcmp(key, "Address") == 0) m_xlxNetworkAddress = value; @@ -144,22 +147,22 @@ bool CConf::read() else if (::strcmp(key, "Debug") == 0) m_xlxNetworkDebug = ::atoi(value) == 1; } else if (section == SECTION_DMR_NETWORK) { - if (::strcmp(key, "Address") == 0) - m_dmrNetworkAddress = value; - else if (::strcmp(key, "Port") == 0) - m_dmrNetworkPort = (unsigned int)::atoi(value); - else if (::strcmp(key, "Local") == 0) - m_dmrNetworkLocal = (unsigned int)::atoi(value); - else if (::strcmp(key, "Password") == 0) - m_dmrNetworkPassword = value; - else if (::strcmp(key, "Debug") == 0) - m_dmrNetworkDebug = ::atoi(value) == 1; - } - } + if (::strcmp(key, "Address") == 0) + m_dmrNetworkAddress = value; + else if (::strcmp(key, "Port") == 0) + m_dmrNetworkPort = (unsigned int)::atoi(value); + else if (::strcmp(key, "Local") == 0) + m_dmrNetworkLocal = (unsigned int)::atoi(value); + else if (::strcmp(key, "Password") == 0) + m_dmrNetworkPassword = value; + else if (::strcmp(key, "Debug") == 0) + m_dmrNetworkDebug = ::atoi(value) == 1; + } + } - ::fclose(fp); + ::fclose(fp); - return true; + return true; } bool CConf::getDaemon() const @@ -172,6 +175,11 @@ unsigned int CConf::getXLXSlot() const return m_xlxSlot; } +unsigned int CConf::getXLXTG() const +{ + return m_xlxTG; +} + std::string CConf::getRptAddress() const { return m_rptAddress; diff --git a/Conf.h b/Conf.h index 47f5e02..c8ebdcb 100644 --- a/Conf.h +++ b/Conf.h @@ -33,6 +33,7 @@ public: // The General section bool getDaemon() const; unsigned int getXLXSlot() const; + unsigned int getXLXTG() const; unsigned int getTimeout() const; std::string getRptAddress() const; unsigned int getRptPort() const; @@ -65,6 +66,7 @@ private: std::string m_file; bool m_daemon; unsigned int m_xlxSlot; + unsigned int m_xlxTG; std::string m_rptAddress; unsigned int m_rptPort; std::string m_localAddress; diff --git a/DMRDefines.h b/DMRDefines.h index b4fa2be..eb73a27 100644 --- a/DMRDefines.h +++ b/DMRDefines.h @@ -51,6 +51,18 @@ const unsigned char DIRECT_SLOT2_DATA_SYNC[] = {0x0DU, 0x75U, 0x57U, 0xF5U, 0xF const unsigned char SYNC_MASK[] = {0x0FU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xF0U}; +const unsigned char PAYLOAD_LEFT_MASK[] = {0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xF0U}; +const unsigned char PAYLOAD_RIGHT_MASK[] = {0x0FU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU}; + +const unsigned char VOICE_LC_HEADER_CRC_MASK[] = {0x96U, 0x96U, 0x96U}; +const unsigned char TERMINATOR_WITH_LC_CRC_MASK[] = {0x99U, 0x99U, 0x99U}; +const unsigned char PI_HEADER_CRC_MASK[] = {0x69U, 0x69U}; +const unsigned char DATA_HEADER_CRC_MASK[] = {0xCCU, 0xCCU}; +const unsigned char CSBK_CRC_MASK[] = {0xA5U, 0xA5U}; + +const unsigned int DMR_SLOT_TIME = 60U; +const unsigned int AMBE_PER_SLOT = 3U; + const unsigned char DT_MASK = 0x0FU; const unsigned char DT_VOICE_PI_HEADER = 0x00U; const unsigned char DT_VOICE_LC_HEADER = 0x01U; diff --git a/DMREmbeddedData.cpp b/DMREmbeddedData.cpp new file mode 100644 index 0000000..a5a3e42 --- /dev/null +++ b/DMREmbeddedData.cpp @@ -0,0 +1,322 @@ +/* + * Copyright (C) 2015,2016,2017 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 "DMREmbeddedData.h" + +#include "Hamming.h" +#include "Utils.h" +#include "CRC.h" + +#include +#include +#include + +CDMREmbeddedData::CDMREmbeddedData() : +m_raw(NULL), +m_state(LCS_NONE), +m_data(NULL), +m_FLCO(FLCO_GROUP), +m_valid(false) +{ + m_raw = new bool[128U]; + m_data = new bool[72U]; +} + +CDMREmbeddedData::~CDMREmbeddedData() +{ + delete[] m_raw; + delete[] m_data; +} + +// Add LC data (which may consist of 4 blocks) to the data store +bool CDMREmbeddedData::addData(const unsigned char* data, unsigned char lcss) +{ + assert(data != NULL); + + bool rawData[40U]; + CUtils::byteToBitsBE(data[14U], rawData + 0U); + CUtils::byteToBitsBE(data[15U], rawData + 8U); + CUtils::byteToBitsBE(data[16U], rawData + 16U); + CUtils::byteToBitsBE(data[17U], rawData + 24U); + CUtils::byteToBitsBE(data[18U], rawData + 32U); + + // Is this the first block of a 4 block embedded LC ? + if (lcss == 1U) { + for (unsigned int a = 0U; a < 32U; a++) + m_raw[a] = rawData[a + 4U]; + + // Show we are ready for the next LC block + m_state = LCS_FIRST; + m_valid = false; + + return false; + } + + // Is this the 2nd block of a 4 block embedded LC ? + if (lcss == 3U && m_state == LCS_FIRST) { + for (unsigned int a = 0U; a < 32U; a++) + m_raw[a + 32U] = rawData[a + 4U]; + + // Show we are ready for the next LC block + m_state = LCS_SECOND; + + return false; + } + + // Is this the 3rd block of a 4 block embedded LC ? + if (lcss == 3U && m_state == LCS_SECOND) { + for (unsigned int a = 0U; a < 32U; a++) + m_raw[a + 64U] = rawData[a + 4U]; + + // Show we are ready for the final LC block + m_state = LCS_THIRD; + + return false; + } + + // Is this the final block of a 4 block embedded LC ? + if (lcss == 2U && m_state == LCS_THIRD) { + for (unsigned int a = 0U; a < 32U; a++) + m_raw[a + 96U] = rawData[a + 4U]; + + // Show that we're not ready for any more data + m_state = LCS_NONE; + + // Process the complete data block + decodeEmbeddedData(); + if (m_valid) + encodeEmbeddedData(); + + return m_valid; + } + + return false; +} + +void CDMREmbeddedData::setLC(const CDMRLC& lc) +{ + lc.getData(m_data); + + m_FLCO = lc.getFLCO(); + m_valid = true; + + encodeEmbeddedData(); +} + +void CDMREmbeddedData::encodeEmbeddedData() +{ + unsigned int crc; + CCRC::encodeFiveBit(m_data, crc); + + bool data[128U]; + ::memset(data, 0x00U, 128U * sizeof(bool)); + + data[106U] = (crc & 0x01U) == 0x01U; + data[90U] = (crc & 0x02U) == 0x02U; + data[74U] = (crc & 0x04U) == 0x04U; + data[58U] = (crc & 0x08U) == 0x08U; + data[42U] = (crc & 0x10U) == 0x10U; + + unsigned int b = 0U; + for (unsigned int a = 0U; a < 11U; a++, b++) + data[a] = m_data[b]; + for (unsigned int a = 16U; a < 27U; a++, b++) + data[a] = m_data[b]; + for (unsigned int a = 32U; a < 42U; a++, b++) + data[a] = m_data[b]; + for (unsigned int a = 48U; a < 58U; a++, b++) + data[a] = m_data[b]; + for (unsigned int a = 64U; a < 74U; a++, b++) + data[a] = m_data[b]; + for (unsigned int a = 80U; a < 90U; a++, b++) + data[a] = m_data[b]; + for (unsigned int a = 96U; a < 106U; a++, b++) + data[a] = m_data[b]; + + // Hamming (16,11,4) check each row except the last one + for (unsigned int a = 0U; a < 112U; a += 16U) + CHamming::encode16114(data + a); + + // Add the parity bits for each column + for (unsigned int a = 0U; a < 16U; a++) + data[a + 112U] = data[a + 0U] ^ data[a + 16U] ^ data[a + 32U] ^ data[a + 48U] ^ data[a + 64U] ^ data[a + 80U] ^ data[a + 96U]; + + // The data is packed downwards in columns + b = 0U; + for (unsigned int a = 0U; a < 128U; a++) { + m_raw[a] = data[b]; + b += 16U; + if (b > 127U) + b -= 127U; + } +} + +unsigned char CDMREmbeddedData::getData(unsigned char* data, unsigned char n) const +{ + assert(data != NULL); + + if (n >= 1U && n < 5U) { + n--; + + bool bits[40U]; + ::memset(bits, 0x00U, 40U * sizeof(bool)); + ::memcpy(bits + 4U, m_raw + n * 32U, 32U * sizeof(bool)); + + unsigned char bytes[5U]; + CUtils::bitsToByteBE(bits + 0U, bytes[0U]); + CUtils::bitsToByteBE(bits + 8U, bytes[1U]); + CUtils::bitsToByteBE(bits + 16U, bytes[2U]); + CUtils::bitsToByteBE(bits + 24U, bytes[3U]); + CUtils::bitsToByteBE(bits + 32U, bytes[4U]); + + data[14U] = (data[14U] & 0xF0U) | (bytes[0U] & 0x0FU); + data[15U] = bytes[1U]; + data[16U] = bytes[2U]; + data[17U] = bytes[3U]; + data[18U] = (data[18U] & 0x0FU) | (bytes[4U] & 0xF0U); + + switch (n) { + case 0U: + return 1U; + case 3U: + return 2U; + default: + return 3U; + } + } else { + data[14U] &= 0xF0U; + data[15U] = 0x00U; + data[16U] = 0x00U; + data[17U] = 0x00U; + data[18U] &= 0x0FU; + + return 0U; + } +} + +// Unpack and error check an embedded LC +void CDMREmbeddedData::decodeEmbeddedData() +{ + // The data is unpacked downwards in columns + bool data[128U]; + ::memset(data, 0x00U, 128U * sizeof(bool)); + + unsigned int b = 0U; + for (unsigned int a = 0U; a < 128U; a++) { + data[b] = m_raw[a]; + b += 16U; + if (b > 127U) + b -= 127U; + } + + // Hamming (16,11,4) check each row except the last one + for (unsigned int a = 0U; a < 112U; a += 16U) { + if (!CHamming::decode16114(data + a)) + return; + } + + // Check the parity bits + for (unsigned int a = 0U; a < 16U; a++) { + bool parity = data[a + 0U] ^ data[a + 16U] ^ data[a + 32U] ^ data[a + 48U] ^ data[a + 64U] ^ data[a + 80U] ^ data[a + 96U] ^ data[a + 112U]; + if (parity) + return; + } + + // We have passed the Hamming check so extract the actual payload + b = 0U; + for (unsigned int a = 0U; a < 11U; a++, b++) + m_data[b] = data[a]; + for (unsigned int a = 16U; a < 27U; a++, b++) + m_data[b] = data[a]; + for (unsigned int a = 32U; a < 42U; a++, b++) + m_data[b] = data[a]; + for (unsigned int a = 48U; a < 58U; a++, b++) + m_data[b] = data[a]; + for (unsigned int a = 64U; a < 74U; a++, b++) + m_data[b] = data[a]; + for (unsigned int a = 80U; a < 90U; a++, b++) + m_data[b] = data[a]; + for (unsigned int a = 96U; a < 106U; a++, b++) + m_data[b] = data[a]; + + // Extract the 5 bit CRC + unsigned int crc = 0U; + if (data[42]) crc += 16U; + if (data[58]) crc += 8U; + if (data[74]) crc += 4U; + if (data[90]) crc += 2U; + if (data[106]) crc += 1U; + + // Now CRC check this + if (!CCRC::checkFiveBit(m_data, crc)) + return; + + m_valid = true; + + // Extract the FLCO + unsigned char flco; + CUtils::bitsToByteBE(m_data + 0U, flco); + m_FLCO = FLCO(flco & 0x3FU); +} + +CDMRLC* CDMREmbeddedData::getLC() const +{ + if (!m_valid) + return NULL; + + if (m_FLCO != FLCO_GROUP && m_FLCO != FLCO_USER_USER) + return NULL; + + return new CDMRLC(m_data); +} + +bool CDMREmbeddedData::isValid() const +{ + return m_valid; +} + +FLCO CDMREmbeddedData::getFLCO() const +{ + return m_FLCO; +} + +void CDMREmbeddedData::reset() +{ + m_state = LCS_NONE; + m_valid = false; +} + +bool CDMREmbeddedData::getRawData(unsigned char* data) const +{ + assert(data != NULL); + + if (!m_valid) + return false; + + CUtils::bitsToByteBE(m_data + 0U, data[0U]); + CUtils::bitsToByteBE(m_data + 8U, data[1U]); + CUtils::bitsToByteBE(m_data + 16U, data[2U]); + CUtils::bitsToByteBE(m_data + 24U, data[3U]); + CUtils::bitsToByteBE(m_data + 32U, data[4U]); + CUtils::bitsToByteBE(m_data + 40U, data[5U]); + CUtils::bitsToByteBE(m_data + 48U, data[6U]); + CUtils::bitsToByteBE(m_data + 56U, data[7U]); + CUtils::bitsToByteBE(m_data + 64U, data[8U]); + + return true; +} diff --git a/DMREmbeddedData.h b/DMREmbeddedData.h new file mode 100644 index 0000000..7222dcd --- /dev/null +++ b/DMREmbeddedData.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2015,2016,2017 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. + */ + +#ifndef DMREmbeddedData_H +#define DMREmbeddedData_H + +#include "DMRDefines.h" +#include "DMRLC.h" + +enum LC_STATE { + LCS_NONE, + LCS_FIRST, + LCS_SECOND, + LCS_THIRD +}; + +class CDMREmbeddedData +{ +public: + CDMREmbeddedData(); + ~CDMREmbeddedData(); + + bool addData(const unsigned char* data, unsigned char lcss); + + CDMRLC* getLC() const; + void setLC(const CDMRLC& lc); + + unsigned char getData(unsigned char* data, unsigned char n) const; + + bool getRawData(unsigned char* data) const; + + bool isValid() const; + FLCO getFLCO() const; + + void reset(); + +private: + bool* m_raw; + LC_STATE m_state; + bool* m_data; + FLCO m_FLCO; + bool m_valid; + + void decodeEmbeddedData(); + void encodeEmbeddedData(); +}; + +#endif diff --git a/DMRFullLC.cpp b/DMRFullLC.cpp new file mode 100644 index 0000000..dbcd6cc --- /dev/null +++ b/DMRFullLC.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2012 by Ian Wraith + * Copyright (C) 2015,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 "DMRFullLC.h" + +#include "DMRDefines.h" +#include "RS129.h" +#include "Utils.h" +#include "Log.h" + +#include +#include + +CDMRFullLC::CDMRFullLC() : +m_bptc() +{ +} + +CDMRFullLC::~CDMRFullLC() +{ +} + +CDMRLC* CDMRFullLC::decode(const unsigned char* data, unsigned char type) +{ + assert(data != NULL); + + unsigned char lcData[12U]; + m_bptc.decode(data, lcData); + + switch (type) { + case DT_VOICE_LC_HEADER: + lcData[9U] ^= VOICE_LC_HEADER_CRC_MASK[0U]; + lcData[10U] ^= VOICE_LC_HEADER_CRC_MASK[1U]; + lcData[11U] ^= VOICE_LC_HEADER_CRC_MASK[2U]; + break; + + case DT_TERMINATOR_WITH_LC: + lcData[9U] ^= TERMINATOR_WITH_LC_CRC_MASK[0U]; + lcData[10U] ^= TERMINATOR_WITH_LC_CRC_MASK[1U]; + lcData[11U] ^= TERMINATOR_WITH_LC_CRC_MASK[2U]; + break; + + default: + ::LogError("Unsupported LC type - %d", int(type)); + return NULL; + } + + if (!CRS129::check(lcData)) + return NULL; + + return new CDMRLC(lcData); +} + +void CDMRFullLC::encode(const CDMRLC& lc, unsigned char* data, unsigned char type) +{ + assert(data != NULL); + + unsigned char lcData[12U]; + lc.getData(lcData); + + unsigned char parity[4U]; + CRS129::encode(lcData, 9U, parity); + + switch (type) { + case DT_VOICE_LC_HEADER: + lcData[9U] = parity[2U] ^ VOICE_LC_HEADER_CRC_MASK[0U]; + lcData[10U] = parity[1U] ^ VOICE_LC_HEADER_CRC_MASK[1U]; + lcData[11U] = parity[0U] ^ VOICE_LC_HEADER_CRC_MASK[2U]; + break; + + case DT_TERMINATOR_WITH_LC: + lcData[9U] = parity[2U] ^ TERMINATOR_WITH_LC_CRC_MASK[0U]; + lcData[10U] = parity[1U] ^ TERMINATOR_WITH_LC_CRC_MASK[1U]; + lcData[11U] = parity[0U] ^ TERMINATOR_WITH_LC_CRC_MASK[2U]; + break; + + default: + ::LogError("Unsupported LC type - %d", int(type)); + return; + } + + m_bptc.encode(lcData, data); +} diff --git a/DMRFullLC.h b/DMRFullLC.h new file mode 100644 index 0000000..d3294ef --- /dev/null +++ b/DMRFullLC.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2015,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. + */ + +#ifndef DMRFullLC_H +#define DMRFullLC_H + +#include "DMRLC.h" +#include "DMRSlotType.h" + +#include "BPTC19696.h" + +class CDMRFullLC +{ +public: + CDMRFullLC(); + ~CDMRFullLC(); + + CDMRLC* decode(const unsigned char* data, unsigned char type); + + void encode(const CDMRLC& lc, unsigned char* data, unsigned char type); + +private: + CBPTC19696 m_bptc; +}; + +#endif + diff --git a/DMRGateway.cpp b/DMRGateway.cpp index 8f19a9e..d46ade5 100644 --- a/DMRGateway.cpp +++ b/DMRGateway.cpp @@ -114,7 +114,9 @@ m_conf(confFile), m_mmdvm(NULL), m_dmrNetwork(NULL), m_xlxNetwork(NULL), -m_reflector(0U) +m_reflector(0U), +m_rptRewrite(), +m_xlxRewrite() { } @@ -226,13 +228,17 @@ int CDMRGateway::run() LogMessage("MMDVM has connected"); - unsigned int xlxSlot = m_conf.getXLXSlot(); - unsigned int timeout = m_conf.getTimeout(); + unsigned int xlxSlot = m_conf.getXLXSlot(); + unsigned int xlxTG = m_conf.getXLXTG(); + unsigned int timeout = m_conf.getTimeout(); LogInfo("Id: %u", m_mmdvm->getId()); LogInfo("XLX Local Slot: %u", xlxSlot); + LogInfo("XLX Local TG: %u", xlxTG); LogInfo("Timeout: %us", timeout); + m_rptRewrite.setParams(xlxSlot, xlxTG); + m_xlxRewrite.setParams(XLX_SLOT, XLX_TG); ret = createDMRNetwork(); if (!ret) @@ -261,8 +267,8 @@ int CDMRGateway::run() FLCO flco = data.getFLCO(); unsigned int id = data.getDstId(); - if (flco == FLCO_GROUP && id == XLX_TG) { - data.setSlotNo(XLX_SLOT); + if (flco == FLCO_GROUP && id == xlxTG) { + m_xlxRewrite.process(data); m_xlxNetwork->write(data); status = DMRGWS_REFLECTOR; timer.start(); @@ -273,7 +279,7 @@ int CDMRGateway::run() m_reflector = reflector; } - data.setSlotNo(XLX_SLOT); + m_xlxRewrite.process(data); m_xlxNetwork->write(data); status = DMRGWS_REFLECTOR; timer.start(); @@ -292,7 +298,7 @@ int CDMRGateway::run() if (status == DMRGWS_NONE || status == DMRGWS_REFLECTOR) { unsigned int slotNo = data.getSlotNo(); if (slotNo == XLX_SLOT) { - data.setSlotNo(xlxSlot); + m_rptRewrite.process(data); m_mmdvm->write(data); status = DMRGWS_REFLECTOR; timer.start(); @@ -307,7 +313,7 @@ int CDMRGateway::run() // Stop BM from using the same TG as XLX unsigned int dstId = data.getDstId(); FLCO flco = data.getFLCO(); - if (flco != FLCO_GROUP || dstId != XLX_TG) { + if (flco != FLCO_GROUP || dstId != xlxTG) { if (status == DMRGWS_NONE || status == DMRGWS_NETWORK) { m_mmdvm->write(data); status = DMRGWS_NETWORK; diff --git a/DMRGateway.h b/DMRGateway.h index c590fc3..b042d81 100644 --- a/DMRGateway.h +++ b/DMRGateway.h @@ -21,6 +21,7 @@ #include "MMDVMNetwork.h" #include "DMRNetwork.h" +#include "Rewrite.h" #include "Conf.h" #include @@ -39,6 +40,8 @@ private: CDMRNetwork* m_dmrNetwork; CDMRNetwork* m_xlxNetwork; unsigned int m_reflector; + CRewrite m_rptRewrite; + CRewrite m_xlxRewrite; bool createMMDVM(); bool createDMRNetwork(); diff --git a/DMRGateway.ini b/DMRGateway.ini index 6bd9734..3feff11 100644 --- a/DMRGateway.ini +++ b/DMRGateway.ini @@ -1,5 +1,6 @@ [General] XLXSlot=2 +XLXTG=9 Timeout=10 RptAddress=127.0.0.1 RptPort=62032 diff --git a/DMRGateway.vcxproj b/DMRGateway.vcxproj index b3a07e6..72a1265 100644 --- a/DMRGateway.vcxproj +++ b/DMRGateway.vcxproj @@ -146,14 +146,24 @@ + + + + + + + + + + @@ -163,12 +173,22 @@ + + + + + + + + + + diff --git a/DMRGateway.vcxproj.filters b/DMRGateway.vcxproj.filters index c7a6705..2c1e3ea 100644 --- a/DMRGateway.vcxproj.filters +++ b/DMRGateway.vcxproj.filters @@ -56,6 +56,36 @@ Header Files + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + @@ -94,5 +124,35 @@ Source Files + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + \ No newline at end of file diff --git a/DMRLC.cpp b/DMRLC.cpp new file mode 100644 index 0000000..8dd897b --- /dev/null +++ b/DMRLC.cpp @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2015,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 "DMRLC.h" + +#include "Utils.h" + +#include +#include + +CDMRLC::CDMRLC(FLCO flco, unsigned int srcId, unsigned int dstId) : +m_PF(false), +m_R(false), +m_FLCO(flco), +m_FID(0U), +m_options(0U), +m_srcId(srcId), +m_dstId(dstId) +{ +} + +CDMRLC::CDMRLC(const unsigned char* bytes) : +m_PF(false), +m_R(false), +m_FLCO(FLCO_GROUP), +m_FID(0U), +m_options(0U), +m_srcId(0U), +m_dstId(0U) +{ + assert(bytes != NULL); + + m_PF = (bytes[0U] & 0x80U) == 0x80U; + m_R = (bytes[0U] & 0x40U) == 0x40U; + + m_FLCO = FLCO(bytes[0U] & 0x3FU); + + m_FID = bytes[1U]; + + m_options = bytes[2U]; + + m_dstId = bytes[3U] << 16 | bytes[4U] << 8 | bytes[5U]; + m_srcId = bytes[6U] << 16 | bytes[7U] << 8 | bytes[8U]; +} + +CDMRLC::CDMRLC(const bool* bits) : +m_PF(false), +m_R(false), +m_FLCO(FLCO_GROUP), +m_FID(0U), +m_options(0U), +m_srcId(0U), +m_dstId(0U) +{ + assert(bits != NULL); + + m_PF = bits[0U]; + m_R = bits[1U]; + + unsigned char temp1, temp2, temp3; + CUtils::bitsToByteBE(bits + 0U, temp1); + m_FLCO = FLCO(temp1 & 0x3FU); + + CUtils::bitsToByteBE(bits + 8U, temp2); + m_FID = temp2; + + CUtils::bitsToByteBE(bits + 16U, temp3); + m_options = temp3; + + unsigned char d1, d2, d3; + CUtils::bitsToByteBE(bits + 24U, d1); + CUtils::bitsToByteBE(bits + 32U, d2); + CUtils::bitsToByteBE(bits + 40U, d3); + + unsigned char s1, s2, s3; + CUtils::bitsToByteBE(bits + 48U, s1); + CUtils::bitsToByteBE(bits + 56U, s2); + CUtils::bitsToByteBE(bits + 64U, s3); + + m_srcId = s1 << 16 | s2 << 8 | s3; + m_dstId = d1 << 16 | d2 << 8 | d3; +} + +CDMRLC::CDMRLC() : +m_PF(false), +m_R(false), +m_FLCO(FLCO_GROUP), +m_FID(0U), +m_options(0U), +m_srcId(0U), +m_dstId(0U) +{ +} + +CDMRLC::~CDMRLC() +{ +} + +void CDMRLC::getData(unsigned char* bytes) const +{ + assert(bytes != NULL); + + bytes[0U] = (unsigned char)m_FLCO; + + if (m_PF) + bytes[0U] |= 0x80U; + + if (m_R) + bytes[0U] |= 0x40U; + + bytes[1U] = m_FID; + + bytes[2U] = m_options; + + bytes[3U] = m_dstId >> 16; + bytes[4U] = m_dstId >> 8; + bytes[5U] = m_dstId >> 0; + + bytes[6U] = m_srcId >> 16; + bytes[7U] = m_srcId >> 8; + bytes[8U] = m_srcId >> 0; +} + +void CDMRLC::getData(bool* bits) const +{ + assert(bits != NULL); + + unsigned char bytes[9U]; + getData(bytes); + + CUtils::byteToBitsBE(bytes[0U], bits + 0U); + CUtils::byteToBitsBE(bytes[1U], bits + 8U); + CUtils::byteToBitsBE(bytes[2U], bits + 16U); + CUtils::byteToBitsBE(bytes[3U], bits + 24U); + CUtils::byteToBitsBE(bytes[4U], bits + 32U); + CUtils::byteToBitsBE(bytes[5U], bits + 40U); + CUtils::byteToBitsBE(bytes[6U], bits + 48U); + CUtils::byteToBitsBE(bytes[7U], bits + 56U); + CUtils::byteToBitsBE(bytes[8U], bits + 64U); +} + +bool CDMRLC::getPF() const +{ + return m_PF; +} + +void CDMRLC::setPF(bool pf) +{ + m_PF = pf; +} + +FLCO CDMRLC::getFLCO() const +{ + return m_FLCO; +} + +void CDMRLC::setFLCO(FLCO flco) +{ + m_FLCO = flco; +} + +unsigned char CDMRLC::getFID() const +{ + return m_FID; +} + +void CDMRLC::setFID(unsigned char fid) +{ + m_FID = fid; +} + +unsigned int CDMRLC::getSrcId() const +{ + return m_srcId; +} + +void CDMRLC::setSrcId(unsigned int id) +{ + m_srcId = id; +} + +unsigned int CDMRLC::getDstId() const +{ + return m_dstId; +} + +void CDMRLC::setDstId(unsigned int id) +{ + m_dstId = id; +} diff --git a/DMRLC.h b/DMRLC.h new file mode 100644 index 0000000..9f3a464 --- /dev/null +++ b/DMRLC.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2015,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(DMRLC_H) +#define DMRLC_H + +#include "DMRDefines.h" + +class CDMRLC +{ +public: + CDMRLC(FLCO flco, unsigned int srcId, unsigned int dstId); + CDMRLC(const unsigned char* bytes); + CDMRLC(const bool* bits); + CDMRLC(); + ~CDMRLC(); + + void getData(unsigned char* bytes) const; + void getData(bool* bits) const; + + bool getPF() const; + void setPF(bool pf); + + FLCO getFLCO() const; + void setFLCO(FLCO flco); + + unsigned char getFID() const; + void setFID(unsigned char fid); + + unsigned int getSrcId() const; + void setSrcId(unsigned int id); + + unsigned int getDstId() const; + void setDstId(unsigned int id); + +private: + bool m_PF; + bool m_R; + FLCO m_FLCO; + unsigned char m_FID; + unsigned char m_options; + unsigned int m_srcId; + unsigned int m_dstId; +}; + +#endif + diff --git a/DMRSlotType.cpp b/DMRSlotType.cpp new file mode 100644 index 0000000..d855303 --- /dev/null +++ b/DMRSlotType.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2015,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 "DMRSlotType.h" + +#include "Golay2087.h" + +#include +#include + +CDMRSlotType::CDMRSlotType() : +m_colorCode(0U), +m_dataType(0U) +{ +} + +CDMRSlotType::~CDMRSlotType() +{ +} + +void CDMRSlotType::putData(const unsigned char* data) +{ + assert(data != NULL); + + unsigned char DMRSlotType[3U]; + DMRSlotType[0U] = (data[12U] << 2) & 0xFCU; + DMRSlotType[0U] |= (data[13U] >> 6) & 0x03U; + + DMRSlotType[1U] = (data[13U] << 2) & 0xC0U; + DMRSlotType[1U] |= (data[19U] << 2) & 0x3CU; + DMRSlotType[1U] |= (data[20U] >> 6) & 0x03U; + + DMRSlotType[2U] = (data[20U] << 2) & 0xF0U; + + unsigned char code = CGolay2087::decode(DMRSlotType); + + m_colorCode = (code >> 4) & 0x0FU; + m_dataType = (code >> 0) & 0x0FU; +} + +void CDMRSlotType::getData(unsigned char* data) const +{ + assert(data != NULL); + + unsigned char DMRSlotType[3U]; + DMRSlotType[0U] = (m_colorCode << 4) & 0xF0U; + DMRSlotType[0U] |= (m_dataType << 0) & 0x0FU; + DMRSlotType[1U] = 0x00U; + DMRSlotType[2U] = 0x00U; + + CGolay2087::encode(DMRSlotType); + + data[12U] = (data[12U] & 0xC0U) | ((DMRSlotType[0U] >> 2) & 0x3FU); + data[13U] = (data[13U] & 0x0FU) | ((DMRSlotType[0U] << 6) & 0xC0U) | ((DMRSlotType[1U] >> 2) & 0x30U); + data[19U] = (data[19U] & 0xF0U) | ((DMRSlotType[1U] >> 2) & 0x0FU); + data[20U] = (data[20U] & 0x03U) | ((DMRSlotType[1U] << 6) & 0xC0U) | ((DMRSlotType[2U] >> 2) & 0x3CU); +} + +unsigned char CDMRSlotType::getColorCode() const +{ + return m_colorCode; +} + +void CDMRSlotType::setColorCode(unsigned char code) +{ + m_colorCode = code; +} + +unsigned char CDMRSlotType::getDataType() const +{ + return m_dataType; +} + +void CDMRSlotType::setDataType(unsigned char type) +{ + m_dataType = type; +} diff --git a/DMRSlotType.h b/DMRSlotType.h new file mode 100644 index 0000000..e76821f --- /dev/null +++ b/DMRSlotType.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2015,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(DMRSLOTTYPE_H) +#define DMRSLOTTYPE_H + +class CDMRSlotType +{ +public: + CDMRSlotType(); + ~CDMRSlotType(); + + void putData(const unsigned char* data); + void getData(unsigned char* data) const; + + unsigned char getColorCode() const; + void setColorCode(unsigned char code); + + unsigned char getDataType() const; + void setDataType(unsigned char type); + +private: + unsigned char m_colorCode; + unsigned char m_dataType; +}; + +#endif diff --git a/Golay2087.cpp b/Golay2087.cpp new file mode 100644 index 0000000..61942d8 --- /dev/null +++ b/Golay2087.cpp @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2015,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 "Golay2087.h" + +#include +#include + +const unsigned int ENCODING_TABLE_2087[] = + {0x0000U, 0xB08EU, 0xE093U, 0x501DU, 0x70A9U, 0xC027U, 0x903AU, 0x20B4U, 0x60DCU, 0xD052U, 0x804FU, 0x30C1U, + 0x1075U, 0xA0FBU, 0xF0E6U, 0x4068U, 0x7036U, 0xC0B8U, 0x90A5U, 0x202BU, 0x009FU, 0xB011U, 0xE00CU, 0x5082U, + 0x10EAU, 0xA064U, 0xF079U, 0x40F7U, 0x6043U, 0xD0CDU, 0x80D0U, 0x305EU, 0xD06CU, 0x60E2U, 0x30FFU, 0x8071U, + 0xA0C5U, 0x104BU, 0x4056U, 0xF0D8U, 0xB0B0U, 0x003EU, 0x5023U, 0xE0ADU, 0xC019U, 0x7097U, 0x208AU, 0x9004U, + 0xA05AU, 0x10D4U, 0x40C9U, 0xF047U, 0xD0F3U, 0x607DU, 0x3060U, 0x80EEU, 0xC086U, 0x7008U, 0x2015U, 0x909BU, + 0xB02FU, 0x00A1U, 0x50BCU, 0xE032U, 0x90D9U, 0x2057U, 0x704AU, 0xC0C4U, 0xE070U, 0x50FEU, 0x00E3U, 0xB06DU, + 0xF005U, 0x408BU, 0x1096U, 0xA018U, 0x80ACU, 0x3022U, 0x603FU, 0xD0B1U, 0xE0EFU, 0x5061U, 0x007CU, 0xB0F2U, + 0x9046U, 0x20C8U, 0x70D5U, 0xC05BU, 0x8033U, 0x30BDU, 0x60A0U, 0xD02EU, 0xF09AU, 0x4014U, 0x1009U, 0xA087U, + 0x40B5U, 0xF03BU, 0xA026U, 0x10A8U, 0x301CU, 0x8092U, 0xD08FU, 0x6001U, 0x2069U, 0x90E7U, 0xC0FAU, 0x7074U, + 0x50C0U, 0xE04EU, 0xB053U, 0x00DDU, 0x3083U, 0x800DU, 0xD010U, 0x609EU, 0x402AU, 0xF0A4U, 0xA0B9U, 0x1037U, + 0x505FU, 0xE0D1U, 0xB0CCU, 0x0042U, 0x20F6U, 0x9078U, 0xC065U, 0x70EBU, 0xA03DU, 0x10B3U, 0x40AEU, 0xF020U, + 0xD094U, 0x601AU, 0x3007U, 0x8089U, 0xC0E1U, 0x706FU, 0x2072U, 0x90FCU, 0xB048U, 0x00C6U, 0x50DBU, 0xE055U, + 0xD00BU, 0x6085U, 0x3098U, 0x8016U, 0xA0A2U, 0x102CU, 0x4031U, 0xF0BFU, 0xB0D7U, 0x0059U, 0x5044U, 0xE0CAU, + 0xC07EU, 0x70F0U, 0x20EDU, 0x9063U, 0x7051U, 0xC0DFU, 0x90C2U, 0x204CU, 0x00F8U, 0xB076U, 0xE06BU, 0x50E5U, + 0x108DU, 0xA003U, 0xF01EU, 0x4090U, 0x6024U, 0xD0AAU, 0x80B7U, 0x3039U, 0x0067U, 0xB0E9U, 0xE0F4U, 0x507AU, + 0x70CEU, 0xC040U, 0x905DU, 0x20D3U, 0x60BBU, 0xD035U, 0x8028U, 0x30A6U, 0x1012U, 0xA09CU, 0xF081U, 0x400FU, + 0x30E4U, 0x806AU, 0xD077U, 0x60F9U, 0x404DU, 0xF0C3U, 0xA0DEU, 0x1050U, 0x5038U, 0xE0B6U, 0xB0ABU, 0x0025U, + 0x2091U, 0x901FU, 0xC002U, 0x708CU, 0x40D2U, 0xF05CU, 0xA041U, 0x10CFU, 0x307BU, 0x80F5U, 0xD0E8U, 0x6066U, + 0x200EU, 0x9080U, 0xC09DU, 0x7013U, 0x50A7U, 0xE029U, 0xB034U, 0x00BAU, 0xE088U, 0x5006U, 0x001BU, 0xB095U, + 0x9021U, 0x20AFU, 0x70B2U, 0xC03CU, 0x8054U, 0x30DAU, 0x60C7U, 0xD049U, 0xF0FDU, 0x4073U, 0x106EU, 0xA0E0U, + 0x90BEU, 0x2030U, 0x702DU, 0xC0A3U, 0xE017U, 0x5099U, 0x0084U, 0xB00AU, 0xF062U, 0x40ECU, 0x10F1U, 0xA07FU, + 0x80CBU, 0x3045U, 0x6058U, 0xD0D6U}; + +const unsigned int DECODING_TABLE_1987[] = + {0x00000U, 0x00001U, 0x00002U, 0x00003U, 0x00004U, 0x00005U, 0x00006U, 0x00007U, 0x00008U, 0x00009U, 0x0000AU, 0x0000BU, 0x0000CU, + 0x0000DU, 0x0000EU, 0x24020U, 0x00010U, 0x00011U, 0x00012U, 0x00013U, 0x00014U, 0x00015U, 0x00016U, 0x00017U, 0x00018U, 0x00019U, + 0x0001AU, 0x0001BU, 0x0001CU, 0x0001DU, 0x48040U, 0x01480U, 0x00020U, 0x00021U, 0x00022U, 0x00023U, 0x00024U, 0x00025U, 0x00026U, + 0x24008U, 0x00028U, 0x00029U, 0x0002AU, 0x24004U, 0x0002CU, 0x24002U, 0x24001U, 0x24000U, 0x00030U, 0x00031U, 0x00032U, 0x08180U, + 0x00034U, 0x00C40U, 0x00036U, 0x00C42U, 0x00038U, 0x43000U, 0x0003AU, 0x43002U, 0x02902U, 0x24012U, 0x02900U, 0x24010U, 0x00040U, + 0x00041U, 0x00042U, 0x00043U, 0x00044U, 0x00045U, 0x00046U, 0x00047U, 0x00048U, 0x00049U, 0x0004AU, 0x02500U, 0x0004CU, 0x0004DU, + 0x48010U, 0x48011U, 0x00050U, 0x00051U, 0x00052U, 0x21200U, 0x00054U, 0x00C20U, 0x48008U, 0x48009U, 0x00058U, 0x00059U, 0x48004U, + 0x48005U, 0x48002U, 0x48003U, 0x48000U, 0x48001U, 0x00060U, 0x00061U, 0x00062U, 0x00063U, 0x00064U, 0x00C10U, 0x10300U, 0x0B000U, + 0x00068U, 0x00069U, 0x01880U, 0x01881U, 0x40181U, 0x40180U, 0x24041U, 0x24040U, 0x00070U, 0x00C04U, 0x00072U, 0x00C06U, 0x00C01U, + 0x00C00U, 0x00C03U, 0x00C02U, 0x05204U, 0x00C0CU, 0x48024U, 0x48025U, 0x05200U, 0x00C08U, 0x48020U, 0x48021U, 0x00080U, 0x00081U, + 0x00082U, 0x00083U, 0x00084U, 0x00085U, 0x00086U, 0x00087U, 0x00088U, 0x00089U, 0x0008AU, 0x50200U, 0x0008CU, 0x0A800U, 0x01411U, + 0x01410U, 0x00090U, 0x00091U, 0x00092U, 0x08120U, 0x00094U, 0x00095U, 0x04A00U, 0x01408U, 0x00098U, 0x00099U, 0x01405U, 0x01404U, + 0x01403U, 0x01402U, 0x01401U, 0x01400U, 0x000A0U, 0x000A1U, 0x000A2U, 0x08110U, 0x000A4U, 0x000A5U, 0x42400U, 0x42401U, 0x000A8U, + 0x000A9U, 0x01840U, 0x01841U, 0x40141U, 0x40140U, 0x24081U, 0x24080U, 0x000B0U, 0x08102U, 0x08101U, 0x08100U, 0x000B4U, 0x08106U, + 0x08105U, 0x08104U, 0x20A01U, 0x20A00U, 0x08109U, 0x08108U, 0x01423U, 0x01422U, 0x01421U, 0x01420U, 0x000C0U, 0x000C1U, 0x000C2U, + 0x000C3U, 0x000C4U, 0x000C5U, 0x000C6U, 0x000C7U, 0x000C8U, 0x000C9U, 0x01820U, 0x01821U, 0x20600U, 0x40120U, 0x16000U, 0x16001U, + 0x000D0U, 0x000D1U, 0x42801U, 0x42800U, 0x03100U, 0x18200U, 0x03102U, 0x18202U, 0x000D8U, 0x000D9U, 0x48084U, 0x01444U, 0x48082U, + 0x01442U, 0x48080U, 0x01440U, 0x000E0U, 0x32000U, 0x01808U, 0x04600U, 0x40109U, 0x40108U, 0x0180CU, 0x4010AU, 0x01802U, 0x40104U, + 0x01800U, 0x01801U, 0x40101U, 0x40100U, 0x01804U, 0x40102U, 0x0A408U, 0x08142U, 0x08141U, 0x08140U, 0x00C81U, 0x00C80U, 0x00C83U, + 0x00C82U, 0x0A400U, 0x0A401U, 0x01810U, 0x01811U, 0x40111U, 0x40110U, 0x01814U, 0x40112U, 0x00100U, 0x00101U, 0x00102U, 0x00103U, + 0x00104U, 0x00105U, 0x00106U, 0x41800U, 0x00108U, 0x00109U, 0x0010AU, 0x02440U, 0x0010CU, 0x0010DU, 0x0010EU, 0x02444U, 0x00110U, + 0x00111U, 0x00112U, 0x080A0U, 0x00114U, 0x00115U, 0x00116U, 0x080A4U, 0x00118U, 0x00119U, 0x15000U, 0x15001U, 0x02822U, 0x02823U, + 0x02820U, 0x02821U, 0x00120U, 0x00121U, 0x00122U, 0x08090U, 0x00124U, 0x00125U, 0x10240U, 0x10241U, 0x00128U, 0x00129U, 0x0012AU, + 0x24104U, 0x09400U, 0x400C0U, 0x02810U, 0x24100U, 0x00130U, 0x08082U, 0x08081U, 0x08080U, 0x31001U, 0x31000U, 0x02808U, 0x08084U, + 0x02806U, 0x0808AU, 0x02804U, 0x08088U, 0x02802U, 0x02803U, 0x02800U, 0x02801U, 0x00140U, 0x00141U, 0x00142U, 0x02408U, 0x00144U, + 0x00145U, 0x10220U, 0x10221U, 0x00148U, 0x02402U, 0x02401U, 0x02400U, 0x400A1U, 0x400A0U, 0x02405U, 0x02404U, 0x00150U, 0x00151U, + 0x00152U, 0x02418U, 0x03080U, 0x03081U, 0x03082U, 0x03083U, 0x09801U, 0x09800U, 0x02411U, 0x02410U, 0x48102U, 0x09804U, 0x48100U, + 0x48101U, 0x00160U, 0x00161U, 0x10204U, 0x10205U, 0x10202U, 0x40088U, 0x10200U, 0x10201U, 0x40085U, 0x40084U, 0x02421U, 0x02420U, + 0x40081U, 0x40080U, 0x10208U, 0x40082U, 0x41402U, 0x080C2U, 0x41400U, 0x080C0U, 0x00D01U, 0x00D00U, 0x10210U, 0x10211U, 0x40095U, + 0x40094U, 0x02844U, 0x080C8U, 0x40091U, 0x40090U, 0x02840U, 0x02841U, 0x00180U, 0x00181U, 0x00182U, 0x08030U, 0x00184U, 0x14400U, + 0x22201U, 0x22200U, 0x00188U, 0x00189U, 0x0018AU, 0x08038U, 0x40061U, 0x40060U, 0x40063U, 0x40062U, 0x00190U, 0x08022U, 0x08021U, + 0x08020U, 0x03040U, 0x03041U, 0x08025U, 0x08024U, 0x40C00U, 0x40C01U, 0x08029U, 0x08028U, 0x2C000U, 0x2C001U, 0x01501U, 0x01500U, + 0x001A0U, 0x08012U, 0x08011U, 0x08010U, 0x40049U, 0x40048U, 0x08015U, 0x08014U, 0x06200U, 0x40044U, 0x30400U, 0x08018U, 0x40041U, + 0x40040U, 0x40043U, 0x40042U, 0x08003U, 0x08002U, 0x08001U, 0x08000U, 0x08007U, 0x08006U, 0x08005U, 0x08004U, 0x0800BU, 0x0800AU, + 0x08009U, 0x08008U, 0x40051U, 0x40050U, 0x02880U, 0x0800CU, 0x001C0U, 0x001C1U, 0x64000U, 0x64001U, 0x03010U, 0x40028U, 0x08C00U, + 0x08C01U, 0x40025U, 0x40024U, 0x02481U, 0x02480U, 0x40021U, 0x40020U, 0x40023U, 0x40022U, 0x03004U, 0x03005U, 0x08061U, 0x08060U, + 0x03000U, 0x03001U, 0x03002U, 0x03003U, 0x0300CU, 0x40034U, 0x30805U, 0x30804U, 0x03008U, 0x40030U, 0x30801U, 0x30800U, 0x4000DU, + 0x4000CU, 0x08051U, 0x08050U, 0x40009U, 0x40008U, 0x10280U, 0x4000AU, 0x40005U, 0x40004U, 0x01900U, 0x40006U, 0x40001U, 0x40000U, + 0x40003U, 0x40002U, 0x14800U, 0x08042U, 0x08041U, 0x08040U, 0x03020U, 0x40018U, 0x08045U, 0x08044U, 0x40015U, 0x40014U, 0x08049U, + 0x08048U, 0x40011U, 0x40010U, 0x40013U, 0x40012U, 0x00200U, 0x00201U, 0x00202U, 0x00203U, 0x00204U, 0x00205U, 0x00206U, 0x00207U, + 0x00208U, 0x00209U, 0x0020AU, 0x50080U, 0x0020CU, 0x0020DU, 0x0020EU, 0x50084U, 0x00210U, 0x00211U, 0x00212U, 0x21040U, 0x00214U, + 0x00215U, 0x04880U, 0x04881U, 0x00218U, 0x00219U, 0x0E001U, 0x0E000U, 0x0021CU, 0x0021DU, 0x04888U, 0x0E004U, 0x00220U, 0x00221U, + 0x00222U, 0x00223U, 0x00224U, 0x00225U, 0x10140U, 0x10141U, 0x00228U, 0x00229U, 0x0022AU, 0x24204U, 0x12401U, 0x12400U, 0x24201U, + 0x24200U, 0x00230U, 0x00231U, 0x00232U, 0x21060U, 0x2A000U, 0x2A001U, 0x2A002U, 0x2A003U, 0x20881U, 0x20880U, 0x20883U, 0x20882U, + 0x05040U, 0x05041U, 0x05042U, 0x24210U, 0x00240U, 0x00241U, 0x00242U, 0x21010U, 0x00244U, 0x46000U, 0x10120U, 0x10121U, 0x00248U, + 0x00249U, 0x0024AU, 0x21018U, 0x20480U, 0x20481U, 0x20482U, 0x20483U, 0x00250U, 0x21002U, 0x21001U, 0x21000U, 0x18081U, 0x18080U, + 0x21005U, 0x21004U, 0x12800U, 0x12801U, 0x21009U, 0x21008U, 0x05020U, 0x05021U, 0x48200U, 0x48201U, 0x00260U, 0x00261U, 0x10104U, + 0x04480U, 0x10102U, 0x10103U, 0x10100U, 0x10101U, 0x62002U, 0x62003U, 0x62000U, 0x62001U, 0x05010U, 0x05011U, 0x10108U, 0x10109U, + 0x0500CU, 0x21022U, 0x21021U, 0x21020U, 0x05008U, 0x00E00U, 0x10110U, 0x10111U, 0x05004U, 0x05005U, 0x05006U, 0x21028U, 0x05000U, + 0x05001U, 0x05002U, 0x05003U, 0x00280U, 0x00281U, 0x00282U, 0x50008U, 0x00284U, 0x00285U, 0x04810U, 0x22100U, 0x00288U, 0x50002U, + 0x50001U, 0x50000U, 0x20440U, 0x20441U, 0x50005U, 0x50004U, 0x00290U, 0x00291U, 0x04804U, 0x04805U, 0x04802U, 0x18040U, 0x04800U, + 0x04801U, 0x20821U, 0x20820U, 0x50011U, 0x50010U, 0x0480AU, 0x01602U, 0x04808U, 0x01600U, 0x002A0U, 0x002A1U, 0x04441U, 0x04440U, + 0x002A4U, 0x002A5U, 0x04830U, 0x04444U, 0x06100U, 0x20810U, 0x50021U, 0x50020U, 0x06104U, 0x20814U, 0x50025U, 0x50024U, 0x20809U, + 0x20808U, 0x13000U, 0x08300U, 0x04822U, 0x2080CU, 0x04820U, 0x04821U, 0x20801U, 0x20800U, 0x20803U, 0x20802U, 0x20805U, 0x20804U, + 0x04828U, 0x20806U, 0x002C0U, 0x002C1U, 0x04421U, 0x04420U, 0x20408U, 0x18010U, 0x2040AU, 0x18012U, 0x20404U, 0x20405U, 0x50041U, + 0x50040U, 0x20400U, 0x20401U, 0x20402U, 0x20403U, 0x18005U, 0x18004U, 0x21081U, 0x21080U, 0x18001U, 0x18000U, 0x04840U, 0x18002U, + 0x20414U, 0x1800CU, 0x21089U, 0x21088U, 0x20410U, 0x18008U, 0x20412U, 0x1800AU, 0x04403U, 0x04402U, 0x04401U, 0x04400U, 0x10182U, + 0x04406U, 0x10180U, 0x04404U, 0x01A02U, 0x0440AU, 0x01A00U, 0x04408U, 0x20420U, 0x40300U, 0x20422U, 0x40302U, 0x04413U, 0x04412U, + 0x04411U, 0x04410U, 0x18021U, 0x18020U, 0x10190U, 0x18022U, 0x20841U, 0x20840U, 0x01A10U, 0x20842U, 0x05080U, 0x05081U, 0x05082U, + 0x05083U, 0x00300U, 0x00301U, 0x00302U, 0x00303U, 0x00304U, 0x00305U, 0x10060U, 0x22080U, 0x00308U, 0x00309U, 0x28800U, 0x28801U, + 0x44402U, 0x44403U, 0x44400U, 0x44401U, 0x00310U, 0x00311U, 0x10C01U, 0x10C00U, 0x00314U, 0x00315U, 0x10070U, 0x10C04U, 0x00318U, + 0x00319U, 0x28810U, 0x10C08U, 0x44412U, 0x00000U, 0x44410U, 0x44411U, 0x00320U, 0x60400U, 0x10044U, 0x10045U, 0x10042U, 0x0C800U, + 0x10040U, 0x10041U, 0x06080U, 0x06081U, 0x06082U, 0x06083U, 0x1004AU, 0x0C808U, 0x10048U, 0x10049U, 0x58008U, 0x08282U, 0x08281U, + 0x08280U, 0x10052U, 0x0C810U, 0x10050U, 0x10051U, 0x58000U, 0x58001U, 0x58002U, 0x08288U, 0x02A02U, 0x02A03U, 0x02A00U, 0x02A01U, + 0x00340U, 0x00341U, 0x10024U, 0x10025U, 0x10022U, 0x10023U, 0x10020U, 0x10021U, 0x34001U, 0x34000U, 0x02601U, 0x02600U, 0x1002AU, + 0x34004U, 0x10028U, 0x10029U, 0x0C400U, 0x0C401U, 0x21101U, 0x21100U, 0x60800U, 0x60801U, 0x10030U, 0x10031U, 0x0C408U, 0x34010U, + 0x21109U, 0x21108U, 0x60808U, 0x60809U, 0x10038U, 0x28420U, 0x10006U, 0x10007U, 0x10004U, 0x10005U, 0x10002U, 0x10003U, 0x10000U, + 0x10001U, 0x1000EU, 0x40284U, 0x1000CU, 0x1000DU, 0x1000AU, 0x40280U, 0x10008U, 0x10009U, 0x10016U, 0x10017U, 0x10014U, 0x10015U, + 0x10012U, 0x10013U, 0x10010U, 0x10011U, 0x05104U, 0x44802U, 0x44801U, 0x44800U, 0x05100U, 0x05101U, 0x10018U, 0x28400U, 0x00380U, + 0x00381U, 0x22005U, 0x22004U, 0x22003U, 0x22002U, 0x22001U, 0x22000U, 0x06020U, 0x06021U, 0x50101U, 0x50100U, 0x11800U, 0x11801U, + 0x22009U, 0x22008U, 0x45001U, 0x45000U, 0x08221U, 0x08220U, 0x04902U, 0x22012U, 0x04900U, 0x22010U, 0x06030U, 0x45008U, 0x08229U, + 0x08228U, 0x11810U, 0x11811U, 0x04908U, 0x22018U, 0x06008U, 0x06009U, 0x08211U, 0x08210U, 0x100C2U, 0x22022U, 0x100C0U, 0x22020U, + 0x06000U, 0x06001U, 0x06002U, 0x06003U, 0x06004U, 0x40240U, 0x06006U, 0x40242U, 0x08203U, 0x08202U, 0x08201U, 0x08200U, 0x08207U, + 0x08206U, 0x08205U, 0x08204U, 0x06010U, 0x20900U, 0x08209U, 0x08208U, 0x61002U, 0x20904U, 0x61000U, 0x61001U, 0x29020U, 0x29021U, + 0x100A4U, 0x22044U, 0x100A2U, 0x22042U, 0x100A0U, 0x22040U, 0x20504U, 0x40224U, 0x0D005U, 0x0D004U, 0x20500U, 0x40220U, 0x0D001U, + 0x0D000U, 0x03204U, 0x18104U, 0x08261U, 0x08260U, 0x03200U, 0x18100U, 0x03202U, 0x18102U, 0x11421U, 0x11420U, 0x00000U, 0x11422U, + 0x03208U, 0x18108U, 0x0D011U, 0x0D010U, 0x29000U, 0x29001U, 0x10084U, 0x04500U, 0x10082U, 0x40208U, 0x10080U, 0x10081U, 0x06040U, + 0x40204U, 0x06042U, 0x40206U, 0x40201U, 0x40200U, 0x10088U, 0x40202U, 0x29010U, 0x08242U, 0x08241U, 0x08240U, 0x10092U, 0x40218U, + 0x10090U, 0x10091U, 0x11401U, 0x11400U, 0x11403U, 0x11402U, 0x40211U, 0x40210U, 0x10098U, 0x40212U, 0x00400U, 0x00401U, 0x00402U, + 0x00403U, 0x00404U, 0x00405U, 0x00406U, 0x00407U, 0x00408U, 0x00409U, 0x0040AU, 0x02140U, 0x0040CU, 0x0040DU, 0x01091U, 0x01090U, + 0x00410U, 0x00411U, 0x00412U, 0x00413U, 0x00414U, 0x00860U, 0x01089U, 0x01088U, 0x00418U, 0x38000U, 0x01085U, 0x01084U, 0x01083U, + 0x01082U, 0x01081U, 0x01080U, 0x00420U, 0x00421U, 0x00422U, 0x00423U, 0x00424U, 0x00850U, 0x42080U, 0x42081U, 0x00428U, 0x00429U, + 0x48801U, 0x48800U, 0x09100U, 0x12200U, 0x24401U, 0x24400U, 0x00430U, 0x00844U, 0x00432U, 0x00846U, 0x00841U, 0x00840U, 0x1C000U, + 0x00842U, 0x00438U, 0x0084CU, 0x010A5U, 0x010A4U, 0x00849U, 0x00848U, 0x010A1U, 0x010A0U, 0x00440U, 0x00441U, 0x00442U, 0x02108U, + 0x00444U, 0x00830U, 0x70001U, 0x70000U, 0x00448U, 0x02102U, 0x02101U, 0x02100U, 0x20280U, 0x20281U, 0x02105U, 0x02104U, 0x00450U, + 0x00824U, 0x00452U, 0x00826U, 0x00821U, 0x00820U, 0x00823U, 0x00822U, 0x24802U, 0x02112U, 0x24800U, 0x02110U, 0x00829U, 0x00828U, + 0x48400U, 0x010C0U, 0x00460U, 0x00814U, 0x04281U, 0x04280U, 0x00811U, 0x00810U, 0x00813U, 0x00812U, 0x54000U, 0x54001U, 0x02121U, + 0x02120U, 0x00819U, 0x00818U, 0x0081BU, 0x0081AU, 0x00805U, 0x00804U, 0x41100U, 0x00806U, 0x00801U, 0x00800U, 0x00803U, 0x00802U, + 0x0A080U, 0x0080CU, 0x0A082U, 0x0080EU, 0x00809U, 0x00808U, 0x0080BU, 0x0080AU, 0x00480U, 0x00481U, 0x00482U, 0x00483U, 0x00484U, + 0x14100U, 0x42020U, 0x01018U, 0x00488U, 0x00489U, 0x01015U, 0x01014U, 0x20240U, 0x01012U, 0x01011U, 0x01010U, 0x00490U, 0x00491U, + 0x0100DU, 0x0100CU, 0x0100BU, 0x0100AU, 0x01009U, 0x01008U, 0x40900U, 0x01006U, 0x01005U, 0x01004U, 0x01003U, 0x01002U, 0x01001U, + 0x01000U, 0x004A0U, 0x004A1U, 0x42004U, 0x04240U, 0x42002U, 0x42003U, 0x42000U, 0x42001U, 0x30102U, 0x30103U, 0x30100U, 0x30101U, + 0x4200AU, 0x01032U, 0x42008U, 0x01030U, 0x25000U, 0x25001U, 0x08501U, 0x08500U, 0x008C1U, 0x008C0U, 0x42010U, 0x01028U, 0x0A040U, + 0x0A041U, 0x01025U, 0x01024U, 0x01023U, 0x01022U, 0x01021U, 0x01020U, 0x004C0U, 0x49000U, 0x04221U, 0x04220U, 0x20208U, 0x20209U, + 0x08900U, 0x08901U, 0x20204U, 0x20205U, 0x02181U, 0x02180U, 0x20200U, 0x20201U, 0x20202U, 0x01050U, 0x0A028U, 0x008A4U, 0x0104DU, + 0x0104CU, 0x008A1U, 0x008A0U, 0x01049U, 0x01048U, 0x0A020U, 0x0A021U, 0x01045U, 0x01044U, 0x20210U, 0x01042U, 0x01041U, 0x01040U, + 0x04203U, 0x04202U, 0x04201U, 0x04200U, 0x00891U, 0x00890U, 0x42040U, 0x04204U, 0x0A010U, 0x0A011U, 0x01C00U, 0x04208U, 0x20220U, + 0x40500U, 0x20222U, 0x40502U, 0x0A008U, 0x00884U, 0x04211U, 0x04210U, 0x00881U, 0x00880U, 0x00883U, 0x00882U, 0x0A000U, 0x0A001U, + 0x0A002U, 0x0A003U, 0x0A004U, 0x00888U, 0x01061U, 0x01060U, 0x00500U, 0x00501U, 0x00502U, 0x02048U, 0x00504U, 0x14080U, 0x00506U, + 0x14082U, 0x00508U, 0x02042U, 0x02041U, 0x02040U, 0x09020U, 0x09021U, 0x44200U, 0x02044U, 0x00510U, 0x00511U, 0x10A01U, 0x10A00U, + 0x4A001U, 0x4A000U, 0x4A003U, 0x4A002U, 0x40880U, 0x40881U, 0x02051U, 0x02050U, 0x40884U, 0x01182U, 0x01181U, 0x01180U, 0x00520U, + 0x60200U, 0x00522U, 0x60202U, 0x09008U, 0x09009U, 0x0900AU, 0x0900BU, 0x09004U, 0x09005U, 0x30080U, 0x02060U, 0x09000U, 0x09001U, + 0x09002U, 0x09003U, 0x41042U, 0x08482U, 0x41040U, 0x08480U, 0x00941U, 0x00940U, 0x41044U, 0x00942U, 0x09014U, 0x09015U, 0x02C04U, + 0x08488U, 0x09010U, 0x09011U, 0x02C00U, 0x02C01U, 0x00540U, 0x0200AU, 0x02009U, 0x02008U, 0x08882U, 0x0200EU, 0x08880U, 0x0200CU, + 0x02003U, 0x02002U, 0x02001U, 0x02000U, 0x02007U, 0x02006U, 0x02005U, 0x02004U, 0x0C200U, 0x0C201U, 0x41020U, 0x02018U, 0x00921U, + 0x00920U, 0x41024U, 0x00922U, 0x02013U, 0x02012U, 0x02011U, 0x02010U, 0x02017U, 0x02016U, 0x02015U, 0x02014U, 0x41012U, 0x0202AU, + 0x41010U, 0x02028U, 0x26000U, 0x00910U, 0x10600U, 0x10601U, 0x02023U, 0x02022U, 0x02021U, 0x02020U, 0x09040U, 0x40480U, 0x02025U, + 0x02024U, 0x41002U, 0x00904U, 0x41000U, 0x41001U, 0x00901U, 0x00900U, 0x41004U, 0x00902U, 0x4100AU, 0x02032U, 0x41008U, 0x02030U, + 0x00909U, 0x00908U, 0x28201U, 0x28200U, 0x00580U, 0x14004U, 0x00582U, 0x14006U, 0x14001U, 0x14000U, 0x08840U, 0x14002U, 0x40810U, + 0x40811U, 0x30020U, 0x020C0U, 0x14009U, 0x14008U, 0x01111U, 0x01110U, 0x40808U, 0x40809U, 0x08421U, 0x08420U, 0x14011U, 0x14010U, + 0x01109U, 0x01108U, 0x40800U, 0x40801U, 0x40802U, 0x01104U, 0x40804U, 0x01102U, 0x01101U, 0x01100U, 0x03801U, 0x03800U, 0x30008U, + 0x08410U, 0x14021U, 0x14020U, 0x42100U, 0x42101U, 0x30002U, 0x30003U, 0x30000U, 0x30001U, 0x09080U, 0x40440U, 0x30004U, 0x30005U, + 0x08403U, 0x08402U, 0x08401U, 0x08400U, 0x08407U, 0x08406U, 0x08405U, 0x08404U, 0x40820U, 0x40821U, 0x30010U, 0x08408U, 0x40824U, + 0x01122U, 0x01121U, 0x01120U, 0x08806U, 0x0208AU, 0x08804U, 0x02088U, 0x08802U, 0x14040U, 0x08800U, 0x08801U, 0x02083U, 0x02082U, + 0x02081U, 0x02080U, 0x20300U, 0x40420U, 0x08808U, 0x02084U, 0x03404U, 0x03405U, 0x08814U, 0x02098U, 0x03400U, 0x03401U, 0x08810U, + 0x08811U, 0x40840U, 0x40841U, 0x02091U, 0x02090U, 0x40844U, 0x01142U, 0x01141U, 0x01140U, 0x04303U, 0x04302U, 0x04301U, 0x04300U, + 0x40409U, 0x40408U, 0x08820U, 0x08821U, 0x40405U, 0x40404U, 0x30040U, 0x020A0U, 0x40401U, 0x40400U, 0x40403U, 0x40402U, 0x41082U, + 0x08442U, 0x41080U, 0x08440U, 0x00981U, 0x00980U, 0x41084U, 0x00982U, 0x0A100U, 0x11200U, 0x0A102U, 0x11202U, 0x40411U, 0x40410U, + 0x40413U, 0x40412U, 0x00600U, 0x00601U, 0x00602U, 0x00603U, 0x00604U, 0x00605U, 0x00606U, 0x00607U, 0x00608U, 0x05800U, 0x0060AU, + 0x05802U, 0x200C0U, 0x12020U, 0x44100U, 0x44101U, 0x00610U, 0x00611U, 0x10901U, 0x10900U, 0x51000U, 0x51001U, 0x51002U, 0x10904U, + 0x00618U, 0x05810U, 0x01285U, 0x01284U, 0x51008U, 0x01282U, 0x01281U, 0x01280U, 0x00620U, 0x60100U, 0x040C1U, 0x040C0U, 0x12009U, + 0x12008U, 0x21800U, 0x21801U, 0x12005U, 0x12004U, 0x12007U, 0x12006U, 0x12001U, 0x12000U, 0x12003U, 0x12002U, 0x00630U, 0x00A44U, + 0x040D1U, 0x040D0U, 0x00A41U, 0x00A40U, 0x21810U, 0x00A42U, 0x12015U, 0x12014U, 0x00000U, 0x12016U, 0x12011U, 0x12010U, 0x12013U, + 0x12012U, 0x00640U, 0x00641U, 0x040A1U, 0x040A0U, 0x20088U, 0x20089U, 0x2008AU, 0x040A4U, 0x20084U, 0x20085U, 0x19000U, 0x02300U, + 0x20080U, 0x20081U, 0x20082U, 0x20083U, 0x0C100U, 0x0C101U, 0x21401U, 0x21400U, 0x00A21U, 0x00A20U, 0x00A23U, 0x00A22U, 0x20094U, + 0x20095U, 0x19010U, 0x21408U, 0x20090U, 0x20091U, 0x20092U, 0x28120U, 0x04083U, 0x04082U, 0x04081U, 0x04080U, 0x00A11U, 0x00A10U, + 0x10500U, 0x04084U, 0x200A4U, 0x0408AU, 0x04089U, 0x04088U, 0x200A0U, 0x12040U, 0x200A2U, 0x12042U, 0x00A05U, 0x00A04U, 0x04091U, + 0x04090U, 0x00A01U, 0x00A00U, 0x00A03U, 0x00A02U, 0x05404U, 0x00A0CU, 0x28105U, 0x28104U, 0x05400U, 0x00A08U, 0x28101U, 0x28100U, + 0x00680U, 0x00681U, 0x04061U, 0x04060U, 0x20048U, 0x20049U, 0x2004AU, 0x04064U, 0x20044U, 0x20045U, 0x50401U, 0x50400U, 0x20040U, + 0x20041U, 0x20042U, 0x01210U, 0x68002U, 0x68003U, 0x68000U, 0x68001U, 0x04C02U, 0x0120AU, 0x04C00U, 0x01208U, 0x20054U, 0x01206U, + 0x01205U, 0x01204U, 0x20050U, 0x01202U, 0x01201U, 0x01200U, 0x18800U, 0x04042U, 0x04041U, 0x04040U, 0x42202U, 0x04046U, 0x42200U, + 0x04044U, 0x20064U, 0x0404AU, 0x04049U, 0x04048U, 0x20060U, 0x12080U, 0x20062U, 0x12082U, 0x18810U, 0x04052U, 0x04051U, 0x04050U, + 0x4C009U, 0x4C008U, 0x42210U, 0x04054U, 0x20C01U, 0x20C00U, 0x20C03U, 0x20C02U, 0x4C001U, 0x4C000U, 0x01221U, 0x01220U, 0x2000CU, + 0x04022U, 0x04021U, 0x04020U, 0x20008U, 0x20009U, 0x2000AU, 0x04024U, 0x20004U, 0x20005U, 0x20006U, 0x04028U, 0x20000U, 0x20001U, + 0x20002U, 0x20003U, 0x2001CU, 0x04032U, 0x04031U, 0x04030U, 0x20018U, 0x18400U, 0x2001AU, 0x18402U, 0x20014U, 0x20015U, 0x20016U, + 0x01244U, 0x20010U, 0x20011U, 0x20012U, 0x01240U, 0x04003U, 0x04002U, 0x04001U, 0x04000U, 0x20028U, 0x04006U, 0x04005U, 0x04004U, + 0x20024U, 0x0400AU, 0x04009U, 0x04008U, 0x20020U, 0x20021U, 0x20022U, 0x0400CU, 0x04013U, 0x04012U, 0x04011U, 0x04010U, 0x00A81U, + 0x00A80U, 0x04015U, 0x04014U, 0x0A200U, 0x11100U, 0x04019U, 0x04018U, 0x20030U, 0x20031U, 0x50800U, 0x50801U, 0x00700U, 0x60020U, + 0x10811U, 0x10810U, 0x4400AU, 0x60024U, 0x44008U, 0x44009U, 0x44006U, 0x02242U, 0x44004U, 0x02240U, 0x44002U, 0x44003U, 0x44000U, + 0x44001U, 0x0C040U, 0x10802U, 0x10801U, 0x10800U, 0x0C044U, 0x10806U, 0x10805U, 0x10804U, 0x23000U, 0x23001U, 0x10809U, 0x10808U, + 0x44012U, 0x44013U, 0x44010U, 0x44011U, 0x60001U, 0x60000U, 0x60003U, 0x60002U, 0x60005U, 0x60004U, 0x10440U, 0x10441U, 0x60009U, + 0x60008U, 0x44024U, 0x6000AU, 0x09200U, 0x12100U, 0x44020U, 0x44021U, 0x60011U, 0x60010U, 0x10821U, 0x10820U, 0x07003U, 0x07002U, + 0x07001U, 0x07000U, 0x23020U, 0x60018U, 0x28045U, 0x28044U, 0x09210U, 0x28042U, 0x28041U, 0x28040U, 0x0C010U, 0x0C011U, 0x02209U, + 0x02208U, 0x10422U, 0x10423U, 0x10420U, 0x10421U, 0x02203U, 0x02202U, 0x02201U, 0x02200U, 0x20180U, 0x20181U, 0x44040U, 0x02204U, + 0x0C000U, 0x0C001U, 0x0C002U, 0x10840U, 0x0C004U, 0x0C005U, 0x0C006U, 0x10844U, 0x0C008U, 0x0C009U, 0x02211U, 0x02210U, 0x0C00CU, + 0x28022U, 0x28021U, 0x28020U, 0x60041U, 0x60040U, 0x10404U, 0x04180U, 0x10402U, 0x10403U, 0x10400U, 0x10401U, 0x02223U, 0x02222U, + 0x02221U, 0x02220U, 0x1040AU, 0x28012U, 0x10408U, 0x28010U, 0x0C020U, 0x0C021U, 0x41200U, 0x41201U, 0x00B01U, 0x00B00U, 0x10410U, + 0x28008U, 0x11081U, 0x11080U, 0x28005U, 0x28004U, 0x28003U, 0x28002U, 0x28001U, 0x28000U, 0x52040U, 0x14204U, 0x22405U, 0x22404U, + 0x14201U, 0x14200U, 0x22401U, 0x22400U, 0x20144U, 0x20145U, 0x44084U, 0x022C0U, 0x20140U, 0x20141U, 0x44080U, 0x44081U, 0x40A08U, + 0x10882U, 0x10881U, 0x10880U, 0x14211U, 0x14210U, 0x1A008U, 0x10884U, 0x40A00U, 0x40A01U, 0x40A02U, 0x01304U, 0x1A002U, 0x01302U, + 0x1A000U, 0x01300U, 0x60081U, 0x60080U, 0x04141U, 0x04140U, 0x60085U, 0x60084U, 0x104C0U, 0x04144U, 0x06400U, 0x06401U, 0x30200U, + 0x30201U, 0x06404U, 0x40640U, 0x30204U, 0x30205U, 0x08603U, 0x08602U, 0x08601U, 0x08600U, 0x00000U, 0x08606U, 0x08605U, 0x08604U, + 0x11041U, 0x11040U, 0x30210U, 0x11042U, 0x11045U, 0x11044U, 0x1A020U, 0x01320U, 0x52000U, 0x52001U, 0x04121U, 0x04120U, 0x20108U, + 0x20109U, 0x08A00U, 0x08A01U, 0x20104U, 0x20105U, 0x02281U, 0x02280U, 0x20100U, 0x20101U, 0x20102U, 0x20103U, 0x0C080U, 0x0C081U, + 0x0C082U, 0x04130U, 0x0C084U, 0x06808U, 0x08A10U, 0x08A11U, 0x11021U, 0x11020U, 0x11023U, 0x11022U, 0x20110U, 0x06800U, 0x20112U, + 0x06802U, 0x04103U, 0x04102U, 0x04101U, 0x04100U, 0x10482U, 0x04106U, 0x10480U, 0x04104U, 0x11011U, 0x11010U, 0x04109U, 0x04108U, + 0x20120U, 0x40600U, 0x20122U, 0x40602U, 0x11009U, 0x11008U, 0x22800U, 0x04110U, 0x1100DU, 0x1100CU, 0x22804U, 0x04114U, 0x11001U, + 0x11000U, 0x11003U, 0x11002U, 0x11005U, 0x11004U, 0x28081U, 0x28080U}; + +#define X18 0x00040000 /* vector representation of X^{18} */ +#define X11 0x00000800 /* vector representation of X^{11} */ +#define MASK8 0xfffff800 /* auxiliary vector for testing */ +#define GENPOL 0x00000c75 /* generator polinomial, g(x) */ + +unsigned int CGolay2087::getSyndrome1987(unsigned int pattern) +/* + * Compute the syndrome corresponding to the given pattern, i.e., the + * remainder after dividing the pattern (when considering it as the vector + * representation of a polynomial) by the generator polynomial, GENPOL. + * In the program this pattern has several meanings: (1) pattern = infomation + * bits, when constructing the encoding table; (2) pattern = error pattern, + * when constructing the decoding table; and (3) pattern = received vector, to + * obtain its syndrome in decoding. + */ +{ + unsigned int aux = X18; + + if (pattern >= X11) { + while (pattern & MASK8) { + while (!(aux & pattern)) + aux = aux >> 1; + + pattern ^= (aux / X11) * GENPOL; + } + } + + return pattern; +} + +unsigned char CGolay2087::decode(const unsigned char* data) +{ + assert(data != NULL); + + unsigned int code = (data[0U] << 11) + (data[1U] << 3) + (data[2U] >> 5); + unsigned int syndrome = getSyndrome1987(code); + unsigned int error_pattern = DECODING_TABLE_1987[syndrome]; + + if (error_pattern != 0x00U) + code ^= error_pattern; + + return code >> 11; +} + +void CGolay2087::encode(unsigned char* data) +{ + assert(data != NULL); + + unsigned int value = data[0U]; + + unsigned int cksum = ENCODING_TABLE_2087[value]; + + data[1U] = cksum & 0xFFU; + data[2U] = cksum >> 8; +} diff --git a/Golay2087.h b/Golay2087.h new file mode 100644 index 0000000..d54daed --- /dev/null +++ b/Golay2087.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef Golay2087_H +#define Golay2087_H + +class CGolay2087 { +public: + static void encode(unsigned char* data); + + static unsigned char decode(const unsigned char* data); + +private: + static unsigned int getSyndrome1987(unsigned int pattern); +}; + +#endif diff --git a/Hamming.cpp b/Hamming.cpp new file mode 100644 index 0000000..166e012 --- /dev/null +++ b/Hamming.cpp @@ -0,0 +1,349 @@ +/* + * Copyright (C) 2015,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 "Hamming.h" + +#include +#include + + // Hamming (15,11,3) check a boolean data array +bool CHamming::decode15113_1(bool* d) +{ + assert(d != NULL); + + // Calculate the parity it should have + bool c0 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[6]; + bool c1 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[7] ^ d[8] ^ d[9]; + bool c2 = d[0] ^ d[1] ^ d[4] ^ d[5] ^ d[7] ^ d[8] ^ d[10]; + bool c3 = d[0] ^ d[2] ^ d[4] ^ d[6] ^ d[7] ^ d[9] ^ d[10]; + + unsigned char n = 0U; + n |= (c0 != d[11]) ? 0x01U : 0x00U; + n |= (c1 != d[12]) ? 0x02U : 0x00U; + n |= (c2 != d[13]) ? 0x04U : 0x00U; + n |= (c3 != d[14]) ? 0x08U : 0x00U; + + switch (n) + { + // Parity bit errors + case 0x01U: d[11] = !d[11]; return true; + case 0x02U: d[12] = !d[12]; return true; + case 0x04U: d[13] = !d[13]; return true; + case 0x08U: d[14] = !d[14]; return true; + + // Data bit errors + case 0x0FU: d[0] = !d[0]; return true; + case 0x07U: d[1] = !d[1]; return true; + case 0x0BU: d[2] = !d[2]; return true; + case 0x03U: d[3] = !d[3]; return true; + case 0x0DU: d[4] = !d[4]; return true; + case 0x05U: d[5] = !d[5]; return true; + case 0x09U: d[6] = !d[6]; return true; + case 0x0EU: d[7] = !d[7]; return true; + case 0x06U: d[8] = !d[8]; return true; + case 0x0AU: d[9] = !d[9]; return true; + case 0x0CU: d[10] = !d[10]; return true; + + // No bit errors + default: return false; + } +} + +void CHamming::encode15113_1(bool* d) +{ + assert(d != NULL); + + // Calculate the checksum this row should have + d[11] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[6]; + d[12] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[7] ^ d[8] ^ d[9]; + d[13] = d[0] ^ d[1] ^ d[4] ^ d[5] ^ d[7] ^ d[8] ^ d[10]; + d[14] = d[0] ^ d[2] ^ d[4] ^ d[6] ^ d[7] ^ d[9] ^ d[10]; +} + +// Hamming (15,11,3) check a boolean data array +bool CHamming::decode15113_2(bool* d) +{ + assert(d != NULL); + + // Calculate the checksum this row should have + bool c0 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[5] ^ d[7] ^ d[8]; + bool c1 = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[6] ^ d[8] ^ d[9]; + bool c2 = d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[7] ^ d[9] ^ d[10]; + bool c3 = d[0] ^ d[1] ^ d[2] ^ d[4] ^ d[6] ^ d[7] ^ d[10]; + + unsigned char n = 0x00U; + n |= (c0 != d[11]) ? 0x01U : 0x00U; + n |= (c1 != d[12]) ? 0x02U : 0x00U; + n |= (c2 != d[13]) ? 0x04U : 0x00U; + n |= (c3 != d[14]) ? 0x08U : 0x00U; + + switch (n) { + // Parity bit errors + case 0x01U: d[11] = !d[11]; return true; + case 0x02U: d[12] = !d[12]; return true; + case 0x04U: d[13] = !d[13]; return true; + case 0x08U: d[14] = !d[14]; return true; + + // Data bit errors + case 0x09U: d[0] = !d[0]; return true; + case 0x0BU: d[1] = !d[1]; return true; + case 0x0FU: d[2] = !d[2]; return true; + case 0x07U: d[3] = !d[3]; return true; + case 0x0EU: d[4] = !d[4]; return true; + case 0x05U: d[5] = !d[5]; return true; + case 0x0AU: d[6] = !d[6]; return true; + case 0x0DU: d[7] = !d[7]; return true; + case 0x03U: d[8] = !d[8]; return true; + case 0x06U: d[9] = !d[9]; return true; + case 0x0CU: d[10] = !d[10]; return true; + + // No bit errors + default: return false; + } +} + +void CHamming::encode15113_2(bool* d) +{ + assert(d != NULL); + + // Calculate the checksum this row should have + d[11] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[5] ^ d[7] ^ d[8]; + d[12] = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[6] ^ d[8] ^ d[9]; + d[13] = d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[7] ^ d[9] ^ d[10]; + d[14] = d[0] ^ d[1] ^ d[2] ^ d[4] ^ d[6] ^ d[7] ^ d[10]; +} + +// Hamming (13,9,3) check a boolean data array +bool CHamming::decode1393(bool* d) +{ + assert(d != NULL); + + // Calculate the checksum this column should have + bool c0 = d[0] ^ d[1] ^ d[3] ^ d[5] ^ d[6]; + bool c1 = d[0] ^ d[1] ^ d[2] ^ d[4] ^ d[6] ^ d[7]; + bool c2 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[5] ^ d[7] ^ d[8]; + bool c3 = d[0] ^ d[2] ^ d[4] ^ d[5] ^ d[8]; + + unsigned char n = 0x00U; + n |= (c0 != d[9]) ? 0x01U : 0x00U; + n |= (c1 != d[10]) ? 0x02U : 0x00U; + n |= (c2 != d[11]) ? 0x04U : 0x00U; + n |= (c3 != d[12]) ? 0x08U : 0x00U; + + switch (n) { + // Parity bit errors + case 0x01U: d[9] = !d[9]; return true; + case 0x02U: d[10] = !d[10]; return true; + case 0x04U: d[11] = !d[11]; return true; + case 0x08U: d[12] = !d[12]; return true; + + // Data bit erros + case 0x0FU: d[0] = !d[0]; return true; + case 0x07U: d[1] = !d[1]; return true; + case 0x0EU: d[2] = !d[2]; return true; + case 0x05U: d[3] = !d[3]; return true; + case 0x0AU: d[4] = !d[4]; return true; + case 0x0DU: d[5] = !d[5]; return true; + case 0x03U: d[6] = !d[6]; return true; + case 0x06U: d[7] = !d[7]; return true; + case 0x0CU: d[8] = !d[8]; return true; + + // No bit errors + default: return false; + } +} + +void CHamming::encode1393(bool* d) +{ + assert(d != NULL); + + // Calculate the checksum this column should have + d[9] = d[0] ^ d[1] ^ d[3] ^ d[5] ^ d[6]; + d[10] = d[0] ^ d[1] ^ d[2] ^ d[4] ^ d[6] ^ d[7]; + d[11] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[5] ^ d[7] ^ d[8]; + d[12] = d[0] ^ d[2] ^ d[4] ^ d[5] ^ d[8]; +} + +// Hamming (10,6,3) check a boolean data array +bool CHamming::decode1063(bool* d) +{ + assert(d != NULL); + + // Calculate the checksum this column should have + bool c0 = d[0] ^ d[1] ^ d[2] ^ d[5]; + bool c1 = d[0] ^ d[1] ^ d[3] ^ d[5]; + bool c2 = d[0] ^ d[2] ^ d[3] ^ d[4]; + bool c3 = d[1] ^ d[2] ^ d[3] ^ d[4]; + + unsigned char n = 0x00U; + n |= (c0 != d[6]) ? 0x01U : 0x00U; + n |= (c1 != d[7]) ? 0x02U : 0x00U; + n |= (c2 != d[8]) ? 0x04U : 0x00U; + n |= (c3 != d[9]) ? 0x08U : 0x00U; + + switch (n) { + // Parity bit errors + case 0x01U: d[6] = !d[6]; return true; + case 0x02U: d[7] = !d[7]; return true; + case 0x04U: d[8] = !d[8]; return true; + case 0x08U: d[9] = !d[9]; return true; + + // Data bit erros + case 0x07U: d[0] = !d[0]; return true; + case 0x0BU: d[1] = !d[1]; return true; + case 0x0DU: d[2] = !d[2]; return true; + case 0x0EU: d[3] = !d[3]; return true; + case 0x0CU: d[4] = !d[4]; return true; + case 0x03U: d[5] = !d[5]; return true; + + // No bit errors + default: return false; + } +} + +void CHamming::encode1063(bool* d) +{ + assert(d != NULL); + + // Calculate the checksum this column should have + d[6] = d[0] ^ d[1] ^ d[2] ^ d[5]; + d[7] = d[0] ^ d[1] ^ d[3] ^ d[5]; + d[8] = d[0] ^ d[2] ^ d[3] ^ d[4]; + d[9] = d[1] ^ d[2] ^ d[3] ^ d[4]; +} + +// A Hamming (16,11,4) Check +bool CHamming::decode16114(bool* d) +{ + assert(d != NULL); + + // Calculate the checksum this column should have + bool c0 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[5] ^ d[7] ^ d[8]; + bool c1 = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[6] ^ d[8] ^ d[9]; + bool c2 = d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[7] ^ d[9] ^ d[10]; + bool c3 = d[0] ^ d[1] ^ d[2] ^ d[4] ^ d[6] ^ d[7] ^ d[10]; + bool c4 = d[0] ^ d[2] ^ d[5] ^ d[6] ^ d[8] ^ d[9] ^ d[10]; + + // Compare these with the actual bits + unsigned char n = 0x00U; + n |= (c0 != d[11]) ? 0x01U : 0x00U; + n |= (c1 != d[12]) ? 0x02U : 0x00U; + n |= (c2 != d[13]) ? 0x04U : 0x00U; + n |= (c3 != d[14]) ? 0x08U : 0x00U; + n |= (c4 != d[15]) ? 0x10U : 0x00U; + + switch (n) { + // Parity bit errors + case 0x01U: d[11] = !d[11]; return true; + case 0x02U: d[12] = !d[12]; return true; + case 0x04U: d[13] = !d[13]; return true; + case 0x08U: d[14] = !d[14]; return true; + case 0x10U: d[15] = !d[15]; return true; + + // Data bit errors + case 0x19U: d[0] = !d[0]; return true; + case 0x0BU: d[1] = !d[1]; return true; + case 0x1FU: d[2] = !d[2]; return true; + case 0x07U: d[3] = !d[3]; return true; + case 0x0EU: d[4] = !d[4]; return true; + case 0x15U: d[5] = !d[5]; return true; + case 0x1AU: d[6] = !d[6]; return true; + case 0x0DU: d[7] = !d[7]; return true; + case 0x13U: d[8] = !d[8]; return true; + case 0x16U: d[9] = !d[9]; return true; + case 0x1CU: d[10] = !d[10]; return true; + + // No bit errors + case 0x00U: return true; + + // Unrecoverable errors + default: return false; + } +} + +void CHamming::encode16114(bool* d) +{ + assert(d != NULL); + + d[11] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[5] ^ d[7] ^ d[8]; + d[12] = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[6] ^ d[8] ^ d[9]; + d[13] = d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[7] ^ d[9] ^ d[10]; + d[14] = d[0] ^ d[1] ^ d[2] ^ d[4] ^ d[6] ^ d[7] ^ d[10]; + d[15] = d[0] ^ d[2] ^ d[5] ^ d[6] ^ d[8] ^ d[9] ^ d[10]; +} + +// A Hamming (17,12,3) Check +bool CHamming::decode17123(bool* d) +{ + assert(d != NULL); + + // Calculate the checksum this column should have + bool c0 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[6] ^ d[7] ^ d[9]; + bool c1 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[7] ^ d[8] ^ d[10]; + bool c2 = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[8] ^ d[9] ^ d[11]; + bool c3 = d[0] ^ d[1] ^ d[4] ^ d[5] ^ d[7] ^ d[10]; + bool c4 = d[0] ^ d[1] ^ d[2] ^ d[5] ^ d[6] ^ d[8] ^ d[11]; + + // Compare these with the actual bits + unsigned char n = 0x00U; + n |= (c0 != d[12]) ? 0x01U : 0x00U; + n |= (c1 != d[13]) ? 0x02U : 0x00U; + n |= (c2 != d[14]) ? 0x04U : 0x00U; + n |= (c3 != d[15]) ? 0x08U : 0x00U; + n |= (c4 != d[16]) ? 0x10U : 0x00U; + + switch (n) { + // Parity bit errors + case 0x01U: d[12] = !d[12]; return true; + case 0x02U: d[13] = !d[13]; return true; + case 0x04U: d[14] = !d[14]; return true; + case 0x08U: d[15] = !d[15]; return true; + case 0x10U: d[16] = !d[16]; return true; + + // Data bit errors + case 0x1BU: d[0] = !d[0]; return true; + case 0x1FU: d[1] = !d[1]; return true; + case 0x17U: d[2] = !d[2]; return true; + case 0x07U: d[3] = !d[3]; return true; + case 0x0EU: d[4] = !d[4]; return true; + case 0x1CU: d[5] = !d[5]; return true; + case 0x11U: d[6] = !d[6]; return true; + case 0x0BU: d[7] = !d[7]; return true; + case 0x16U: d[8] = !d[8]; return true; + case 0x05U: d[9] = !d[9]; return true; + case 0x0AU: d[10] = !d[10]; return true; + case 0x14U: d[11] = !d[11]; return true; + + // No bit errors + case 0x00U: return true; + + // Unrecoverable errors + default: return false; + } +} + +void CHamming::encode17123(bool* d) +{ + assert(d != NULL); + + d[12] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[6] ^ d[7] ^ d[9]; + d[13] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[7] ^ d[8] ^ d[10]; + d[14] = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[8] ^ d[9] ^ d[11]; + d[15] = d[0] ^ d[1] ^ d[4] ^ d[5] ^ d[7] ^ d[10]; + d[16] = d[0] ^ d[1] ^ d[2] ^ d[5] ^ d[6] ^ d[8] ^ d[11]; +} diff --git a/Hamming.h b/Hamming.h new file mode 100644 index 0000000..393e005 --- /dev/null +++ b/Hamming.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2015,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. + */ + +#ifndef Hamming_H +#define Hamming_H + +class CHamming { +public: + static void encode15113_1(bool* d); + static bool decode15113_1(bool* d); + + static void encode15113_2(bool* d); + static bool decode15113_2(bool* d); + + static void encode1393(bool* d); + static bool decode1393(bool* d); + + static void encode1063(bool* d); + static bool decode1063(bool* d); + + static void encode16114(bool* d); + static bool decode16114(bool* d); + + static void encode17123(bool* d); + static bool decode17123(bool* d); +}; + +#endif diff --git a/Makefile b/Makefile index 4f5c011..50f7871 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,11 @@ -# This makefile is for all platforms, but doesn't include support for the HD44780 display on the Raspberry Pi. - CC = gcc CXX = g++ CFLAGS = -g -O3 -Wall -std=c++0x -pthread LIBS = -lpthread LDFLAGS = -g -OBJECTS = Conf.o DMRData.o DMRGateway.o DMRNetwork.o Log.o MMDVMNetwork.o SHA256.o StopWatch.o Thread.o Timer.o UDPSocket.o Utils.o +OBJECTS = BPTC19696.o Conf.o CRC.o DMRData.o DMREmbeddedData.o DMRFullLC.o DMRGateway.o DMRLC.o DMRNetwork.o DMRSlotType.o Golay2087.o Hamming.o Log.o MMDVMNetwork.o \ + Rewrite.o RS129.o SHA256.o StopWatch.o Thread.o Timer.o UDPSocket.o Utils.o all: DMRGateway diff --git a/RS129.cpp b/RS129.cpp new file mode 100644 index 0000000..8cad52c --- /dev/null +++ b/RS129.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2015 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 "RS129.h" + +#include +#include +#include + +const unsigned int NPAR = 3U; + +/* Maximum degree of various polynomials. */ +const unsigned int MAXDEG = NPAR * 2U; + +/* Generator Polynomial */ +const unsigned char POLY[] = {64U, 56U, 14U, 1U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U}; + +const unsigned char EXP_TABLE[] = { + 0x01U, 0x02U, 0x04U, 0x08U, 0x10U, 0x20U, 0x40U, 0x80U, 0x1DU, 0x3AU, 0x74U, 0xE8U, 0xCDU, 0x87U, 0x13U, 0x26U, + 0x4CU, 0x98U, 0x2DU, 0x5AU, 0xB4U, 0x75U, 0xEAU, 0xC9U, 0x8FU, 0x03U, 0x06U, 0x0CU, 0x18U, 0x30U, 0x60U, 0xC0U, + 0x9DU, 0x27U, 0x4EU, 0x9CU, 0x25U, 0x4AU, 0x94U, 0x35U, 0x6AU, 0xD4U, 0xB5U, 0x77U, 0xEEU, 0xC1U, 0x9FU, 0x23U, + 0x46U, 0x8CU, 0x05U, 0x0AU, 0x14U, 0x28U, 0x50U, 0xA0U, 0x5DU, 0xBAU, 0x69U, 0xD2U, 0xB9U, 0x6FU, 0xDEU, 0xA1U, + 0x5FU, 0xBEU, 0x61U, 0xC2U, 0x99U, 0x2FU, 0x5EU, 0xBCU, 0x65U, 0xCAU, 0x89U, 0x0FU, 0x1EU, 0x3CU, 0x78U, 0xF0U, + 0xFDU, 0xE7U, 0xD3U, 0xBBU, 0x6BU, 0xD6U, 0xB1U, 0x7FU, 0xFEU, 0xE1U, 0xDFU, 0xA3U, 0x5BU, 0xB6U, 0x71U, 0xE2U, + 0xD9U, 0xAFU, 0x43U, 0x86U, 0x11U, 0x22U, 0x44U, 0x88U, 0x0DU, 0x1AU, 0x34U, 0x68U, 0xD0U, 0xBDU, 0x67U, 0xCEU, + 0x81U, 0x1FU, 0x3EU, 0x7CU, 0xF8U, 0xEDU, 0xC7U, 0x93U, 0x3BU, 0x76U, 0xECU, 0xC5U, 0x97U, 0x33U, 0x66U, 0xCCU, + 0x85U, 0x17U, 0x2EU, 0x5CU, 0xB8U, 0x6DU, 0xDAU, 0xA9U, 0x4FU, 0x9EU, 0x21U, 0x42U, 0x84U, 0x15U, 0x2AU, 0x54U, + 0xA8U, 0x4DU, 0x9AU, 0x29U, 0x52U, 0xA4U, 0x55U, 0xAAU, 0x49U, 0x92U, 0x39U, 0x72U, 0xE4U, 0xD5U, 0xB7U, 0x73U, + 0xE6U, 0xD1U, 0xBFU, 0x63U, 0xC6U, 0x91U, 0x3FU, 0x7EU, 0xFCU, 0xE5U, 0xD7U, 0xB3U, 0x7BU, 0xF6U, 0xF1U, 0xFFU, + 0xE3U, 0xDBU, 0xABU, 0x4BU, 0x96U, 0x31U, 0x62U, 0xC4U, 0x95U, 0x37U, 0x6EU, 0xDCU, 0xA5U, 0x57U, 0xAEU, 0x41U, + 0x82U, 0x19U, 0x32U, 0x64U, 0xC8U, 0x8DU, 0x07U, 0x0EU, 0x1CU, 0x38U, 0x70U, 0xE0U, 0xDDU, 0xA7U, 0x53U, 0xA6U, + 0x51U, 0xA2U, 0x59U, 0xB2U, 0x79U, 0xF2U, 0xF9U, 0xEFU, 0xC3U, 0x9BU, 0x2BU, 0x56U, 0xACU, 0x45U, 0x8AU, 0x09U, + 0x12U, 0x24U, 0x48U, 0x90U, 0x3DU, 0x7AU, 0xF4U, 0xF5U, 0xF7U, 0xF3U, 0xFBU, 0xEBU, 0xCBU, 0x8BU, 0x0BU, 0x16U, + 0x2CU, 0x58U, 0xB0U, 0x7DU, 0xFAU, 0xE9U, 0xCFU, 0x83U, 0x1BU, 0x36U, 0x6CU, 0xD8U, 0xADU, 0x47U, 0x8EU, 0x01U, + 0x02U, 0x04U, 0x08U, 0x10U, 0x20U, 0x40U, 0x80U, 0x1DU, 0x3AU, 0x74U, 0xE8U, 0xCDU, 0x87U, 0x13U, 0x26U, 0x4CU, + 0x98U, 0x2DU, 0x5AU, 0xB4U, 0x75U, 0xEAU, 0xC9U, 0x8FU, 0x03U, 0x06U, 0x0CU, 0x18U, 0x30U, 0x60U, 0xC0U, 0x9DU, + 0x27U, 0x4EU, 0x9CU, 0x25U, 0x4AU, 0x94U, 0x35U, 0x6AU, 0xD4U, 0xB5U, 0x77U, 0xEEU, 0xC1U, 0x9FU, 0x23U, 0x46U, + 0x8CU, 0x05U, 0x0AU, 0x14U, 0x28U, 0x50U, 0xA0U, 0x5DU, 0xBAU, 0x69U, 0xD2U, 0xB9U, 0x6FU, 0xDEU, 0xA1U, 0x5FU, + 0xBEU, 0x61U, 0xC2U, 0x99U, 0x2FU, 0x5EU, 0xBCU, 0x65U, 0xCAU, 0x89U, 0x0FU, 0x1EU, 0x3CU, 0x78U, 0xF0U, 0xFDU, + 0xE7U, 0xD3U, 0xBBU, 0x6BU, 0xD6U, 0xB1U, 0x7FU, 0xFEU, 0xE1U, 0xDFU, 0xA3U, 0x5BU, 0xB6U, 0x71U, 0xE2U, 0xD9U, + 0xAFU, 0x43U, 0x86U, 0x11U, 0x22U, 0x44U, 0x88U, 0x0DU, 0x1AU, 0x34U, 0x68U, 0xD0U, 0xBDU, 0x67U, 0xCEU, 0x81U, + 0x1FU, 0x3EU, 0x7CU, 0xF8U, 0xEDU, 0xC7U, 0x93U, 0x3BU, 0x76U, 0xECU, 0xC5U, 0x97U, 0x33U, 0x66U, 0xCCU, 0x85U, + 0x17U, 0x2EU, 0x5CU, 0xB8U, 0x6DU, 0xDAU, 0xA9U, 0x4FU, 0x9EU, 0x21U, 0x42U, 0x84U, 0x15U, 0x2AU, 0x54U, 0xA8U, + 0x4DU, 0x9AU, 0x29U, 0x52U, 0xA4U, 0x55U, 0xAAU, 0x49U, 0x92U, 0x39U, 0x72U, 0xE4U, 0xD5U, 0xB7U, 0x73U, 0xE6U, + 0xD1U, 0xBFU, 0x63U, 0xC6U, 0x91U, 0x3FU, 0x7EU, 0xFCU, 0xE5U, 0xD7U, 0xB3U, 0x7BU, 0xF6U, 0xF1U, 0xFFU, 0xE3U, + 0xDBU, 0xABU, 0x4BU, 0x96U, 0x31U, 0x62U, 0xC4U, 0x95U, 0x37U, 0x6EU, 0xDCU, 0xA5U, 0x57U, 0xAEU, 0x41U, 0x82U, + 0x19U, 0x32U, 0x64U, 0xC8U, 0x8DU, 0x07U, 0x0EU, 0x1CU, 0x38U, 0x70U, 0xE0U, 0xDDU, 0xA7U, 0x53U, 0xA6U, 0x51U, + 0xA2U, 0x59U, 0xB2U, 0x79U, 0xF2U, 0xF9U, 0xEFU, 0xC3U, 0x9BU, 0x2BU, 0x56U, 0xACU, 0x45U, 0x8AU, 0x09U, 0x12U, + 0x24U, 0x48U, 0x90U, 0x3DU, 0x7AU, 0xF4U, 0xF5U, 0xF7U, 0xF3U, 0xFBU, 0xEBU, 0xCBU, 0x8BU, 0x0BU, 0x16U, 0x2CU, + 0x58U, 0xB0U, 0x7DU, 0xFAU, 0xE9U, 0xCFU, 0x83U, 0x1BU, 0x36U, 0x6CU, 0xD8U, 0xADU, 0x47U, 0x8EU, 0x01U, 0x00U}; + +const unsigned char LOG_TABLE[] = { + 0x00U, 0x00U, 0x01U, 0x19U, 0x02U, 0x32U, 0x1AU, 0xC6U, 0x03U, 0xDFU, 0x33U, 0xEEU, 0x1BU, 0x68U, 0xC7U, 0x4BU, + 0x04U, 0x64U, 0xE0U, 0x0EU, 0x34U, 0x8DU, 0xEFU, 0x81U, 0x1CU, 0xC1U, 0x69U, 0xF8U, 0xC8U, 0x08U, 0x4CU, 0x71U, + 0x05U, 0x8AU, 0x65U, 0x2FU, 0xE1U, 0x24U, 0x0FU, 0x21U, 0x35U, 0x93U, 0x8EU, 0xDAU, 0xF0U, 0x12U, 0x82U, 0x45U, + 0x1DU, 0xB5U, 0xC2U, 0x7DU, 0x6AU, 0x27U, 0xF9U, 0xB9U, 0xC9U, 0x9AU, 0x09U, 0x78U, 0x4DU, 0xE4U, 0x72U, 0xA6U, + 0x06U, 0xBFU, 0x8BU, 0x62U, 0x66U, 0xDDU, 0x30U, 0xFDU, 0xE2U, 0x98U, 0x25U, 0xB3U, 0x10U, 0x91U, 0x22U, 0x88U, + 0x36U, 0xD0U, 0x94U, 0xCEU, 0x8FU, 0x96U, 0xDBU, 0xBDU, 0xF1U, 0xD2U, 0x13U, 0x5CU, 0x83U, 0x38U, 0x46U, 0x40U, + 0x1EU, 0x42U, 0xB6U, 0xA3U, 0xC3U, 0x48U, 0x7EU, 0x6EU, 0x6BU, 0x3AU, 0x28U, 0x54U, 0xFAU, 0x85U, 0xBAU, 0x3DU, + 0xCAU, 0x5EU, 0x9BU, 0x9FU, 0x0AU, 0x15U, 0x79U, 0x2BU, 0x4EU, 0xD4U, 0xE5U, 0xACU, 0x73U, 0xF3U, 0xA7U, 0x57U, + 0x07U, 0x70U, 0xC0U, 0xF7U, 0x8CU, 0x80U, 0x63U, 0x0DU, 0x67U, 0x4AU, 0xDEU, 0xEDU, 0x31U, 0xC5U, 0xFEU, 0x18U, + 0xE3U, 0xA5U, 0x99U, 0x77U, 0x26U, 0xB8U, 0xB4U, 0x7CU, 0x11U, 0x44U, 0x92U, 0xD9U, 0x23U, 0x20U, 0x89U, 0x2EU, + 0x37U, 0x3FU, 0xD1U, 0x5BU, 0x95U, 0xBCU, 0xCFU, 0xCDU, 0x90U, 0x87U, 0x97U, 0xB2U, 0xDCU, 0xFCU, 0xBEU, 0x61U, + 0xF2U, 0x56U, 0xD3U, 0xABU, 0x14U, 0x2AU, 0x5DU, 0x9EU, 0x84U, 0x3CU, 0x39U, 0x53U, 0x47U, 0x6DU, 0x41U, 0xA2U, + 0x1FU, 0x2DU, 0x43U, 0xD8U, 0xB7U, 0x7BU, 0xA4U, 0x76U, 0xC4U, 0x17U, 0x49U, 0xECU, 0x7FU, 0x0CU, 0x6FU, 0xF6U, + 0x6CU, 0xA1U, 0x3BU, 0x52U, 0x29U, 0x9DU, 0x55U, 0xAAU, 0xFBU, 0x60U, 0x86U, 0xB1U, 0xBBU, 0xCCU, 0x3EU, 0x5AU, + 0xCBU, 0x59U, 0x5FU, 0xB0U, 0x9CU, 0xA9U, 0xA0U, 0x51U, 0x0BU, 0xF5U, 0x16U, 0xEBU, 0x7AU, 0x75U, 0x2CU, 0xD7U, + 0x4FU, 0xAEU, 0xD5U, 0xE9U, 0xE6U, 0xE7U, 0xADU, 0xE8U, 0x74U, 0xD6U, 0xF4U, 0xEAU, 0xA8U, 0x50U, 0x58U, 0xAFU}; + +/* multiplication using logarithms */ +static unsigned char gmult(unsigned char a, unsigned char b) +{ + if (a == 0U || b == 0U) + return 0U; + + unsigned int i = LOG_TABLE[a]; + unsigned int j = LOG_TABLE[b]; + + return EXP_TABLE[i + j]; +} + +/* Simulate a LFSR with generator polynomial for n byte RS code. + * Pass in a pointer to the data array, and amount of data. + * + * The parity bytes are deposited into parity. + */ +void CRS129::encode(const unsigned char* msg, unsigned int nbytes, unsigned char* parity) +{ + assert(msg != NULL); + assert(parity != NULL); + + for (unsigned int i = 0U; i < NPAR + 1U; i++) + parity[i] = 0x00U; + + for (unsigned int i = 0U; i < nbytes; i++) { + unsigned char dbyte = msg[i] ^ parity[NPAR - 1U]; + + for (int j = NPAR - 1; j > 0; j--) + parity[j] = parity[j - 1] ^ ::gmult(POLY[j], dbyte); + + parity[0] = ::gmult(POLY[0], dbyte); + } +} + +// Reed-Solomon (12,9) check +bool CRS129::check(const unsigned char* in) +{ + assert(in != NULL); + + unsigned char parity[4U]; + encode(in, 9U, parity); + + return in[9U] == parity[2U] && in[10U] == parity[1U] && in[11U] == parity[0U]; +} + diff --git a/RS129.h b/RS129.h new file mode 100644 index 0000000..60f99bd --- /dev/null +++ b/RS129.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015 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(RS129_H) +#define RS129_H + +class CRS129 +{ +public: + static bool check(const unsigned char* in); + + static void encode(const unsigned char* msg, unsigned int nbytes, unsigned char* parity); +}; + +#endif diff --git a/Rewrite.cpp b/Rewrite.cpp new file mode 100644 index 0000000..11dd715 --- /dev/null +++ b/Rewrite.cpp @@ -0,0 +1,110 @@ +/* +* Copyright (C) 2017 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 "Rewrite.h" + +#include "DMRDefines.h" +#include "DMRFullLC.h" + +#include + +CRewrite::CRewrite() : +m_slot(0U), +m_tg(0U), +m_lc(NULL), +m_embeddedLC() +{ +} + +CRewrite::~CRewrite() +{ +} + +void CRewrite::setParams(unsigned int slot, unsigned int tg) +{ + m_slot = slot; + m_tg = tg; +} + +void CRewrite::process(CDMRData& data) +{ + data.setSlotNo(m_slot); + + FLCO flco = data.getFLCO(); + unsigned int dstId = data.getDstId(); + + if (flco == FLCO_GROUP && dstId != m_tg) { + data.setDstId(m_tg); + + unsigned char dataType = data.getDataType(); + + switch (dataType) { + case DT_VOICE_LC_HEADER: + case DT_TERMINATOR_WITH_LC: + processHeader(data, dataType); + break; + case DT_VOICE: + processVoice(data); + break; + case DT_VOICE_SYNC: + // Nothing to do + break; + default: + // Not sure what to do + break; + } + } +} + +void CRewrite::processHeader(CDMRData& data, unsigned char dataType) +{ + unsigned char buffer[DMR_FRAME_LENGTH_BYTES]; + data.getData(buffer); + + delete m_lc; + m_lc = NULL; + + CDMRFullLC fullLC; + m_lc = fullLC.decode(buffer, dataType); + if (m_lc == NULL) + return; + + m_lc->setDstId(m_tg); + + m_embeddedLC.setLC(*m_lc); + + fullLC.encode(*m_lc, buffer, dataType); + + data.setData(buffer); +} + +void CRewrite::processVoice(CDMRData& data) +{ + if (m_lc == NULL) { + m_lc = new CDMRLC(FLCO_GROUP, data.getSrcId(), m_tg); + m_embeddedLC.setLC(*m_lc); + } + + unsigned char buffer[DMR_FRAME_LENGTH_BYTES]; + data.getData(buffer); + + unsigned char n = data.getN(); + m_embeddedLC.getData(buffer, n); + + data.setData(buffer); +} diff --git a/Rewrite.h b/Rewrite.h new file mode 100644 index 0000000..06f07db --- /dev/null +++ b/Rewrite.h @@ -0,0 +1,46 @@ +/* +* Copyright (C) 2017 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(REWRITE_H) +#define REWRITE_H + +#include "DMREmbeddedData.h" +#include "DMRData.h" +#include "DMRLC.h" + +class CRewrite { +public: + CRewrite(); + ~CRewrite(); + + void setParams(unsigned int slot, unsigned int tg); + + void process(CDMRData& data); + +private: + unsigned int m_slot; + unsigned int m_tg; + CDMRLC* m_lc; + CDMREmbeddedData m_embeddedLC; + + void processHeader(CDMRData& data, unsigned char dataType); + void processVoice(CDMRData& data); +}; + + +#endif diff --git a/Version.h b/Version.h index 8ecec59..4d3dd4f 100644 --- a/Version.h +++ b/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20170427"; +const char* VERSION = "20170428"; #endif