mirror of https://github.com/ShaYmez/MMDVM_CM.git
Add M172DMR
This commit is contained in:
parent
7d6140cbe0
commit
53101450df
|
@ -33,7 +33,7 @@ const char* DEFAULT_INI_FILE = "/etc/DMR2M17.ini";
|
|||
const char* HEADER1 = "This software is for use on amateur radio networks only,";
|
||||
const char* HEADER2 = "it is to be used for educational purposes only. Its use on";
|
||||
const char* HEADER3 = "commercial networks is strictly prohibited.";
|
||||
const char* HEADER4 = "Copyright(C) 2018 by CA6JAU, G4KLX and others";
|
||||
const char* HEADER4 = "Copyright(C) 2018 by AD8DP, CA6JAU, G4KLX and others";
|
||||
|
||||
#define M17CHARACTERS " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/."
|
||||
|
||||
|
@ -370,7 +370,7 @@ int CDMR2M17::run()
|
|||
m17Watch.start();
|
||||
}
|
||||
else if(m17FrameType == TAG_DATA) {
|
||||
//CUtils::dump(1U, "P25 Data", m_p25Frame, 11U);
|
||||
//CUtils::dump(1U, "M17 Data", m_p25Frame, 11U);
|
||||
m17_cnt++;
|
||||
memcpy(buffer, "M17 ", 4);
|
||||
memcpy(buffer+4, &streamid, 2);
|
||||
|
@ -386,7 +386,7 @@ int CDMR2M17::run()
|
|||
}
|
||||
|
||||
while (m_m17Network->readData(m_m17Frame, 54U) > 0U) {
|
||||
//CUtils::dump(1U, "P25 Data", m_p25Frame, 22U);
|
||||
//CUtils::dump(1U, "M17 Data", m_p25Frame, 22U);
|
||||
if (!memcmp(m_m17Frame, "M17 ", 4)) {
|
||||
if (m_m17Frame[34] == 0 && m_m17Frame[35] == 0) {
|
||||
m_m17Frames = 0;
|
||||
|
@ -655,7 +655,7 @@ int CDMR2M17::run()
|
|||
pollTimer.start();
|
||||
}
|
||||
|
||||
|
||||
if (ms < 5U) CThread::sleep(5U);
|
||||
}
|
||||
|
||||
m_m17Network->close();
|
||||
|
|
|
@ -47,7 +47,7 @@ const char* DEFAULT_INI_FILE = "/etc/DMR2YSF.ini";
|
|||
const char* HEADER1 = "This software is for use on amateur radio networks only,";
|
||||
const char* HEADER2 = "it is to be used for educational purposes only. Its use on";
|
||||
const char* HEADER3 = "commercial networks is strictly prohibited.";
|
||||
const char* HEADER4 = "Copyright(C) 2018 by CA6JAU, G4KLX and others";
|
||||
const char* HEADER4 = "Copyright(C) 2018 by CA6JAU, G4KLX, AD8DP and others";
|
||||
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
|
|
|
@ -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 <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
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]);
|
||||
}
|
|
@ -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
|
|
@ -0,0 +1,254 @@
|
|||
/*
|
||||
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||
*
|
||||
* 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 <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
unsigned char CCRC::addCRC(const unsigned char* in, unsigned int length)
|
||||
{
|
||||
assert(in != NULL);
|
||||
|
||||
unsigned char crc = 0U;
|
||||
|
||||
for (unsigned int i = 0U; i < length; i++)
|
||||
crc += in[i];
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||
*
|
||||
* 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);
|
||||
|
||||
static unsigned char addCRC(const unsigned char* in, unsigned int length);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,423 @@
|
|||
/*
|
||||
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||
*
|
||||
* 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 "Conf.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cctype>
|
||||
|
||||
const int BUFFER_SIZE = 500;
|
||||
|
||||
enum SECTION {
|
||||
SECTION_NONE,
|
||||
SECTION_INFO,
|
||||
SECTION_M17_NETWORK,
|
||||
SECTION_DMR_NETWORK,
|
||||
SECTION_DMRID_LOOKUP,
|
||||
SECTION_LOG
|
||||
};
|
||||
|
||||
CConf::CConf(const std::string& file) :
|
||||
m_file(file),
|
||||
m_callsign(),
|
||||
m_tg(20U),
|
||||
m_dstAddress(),
|
||||
m_dstPort(0U),
|
||||
m_localAddress(),
|
||||
m_localPort(0U),
|
||||
m_defaultID(65519U),
|
||||
m_daemon(false),
|
||||
m_rxFrequency(0U),
|
||||
m_txFrequency(0U),
|
||||
m_power(0U),
|
||||
m_latitude(0.0F),
|
||||
m_longitude(0.0F),
|
||||
m_height(0),
|
||||
m_location(),
|
||||
m_description(),
|
||||
m_url(),
|
||||
m_dmrId(0U),
|
||||
m_dmrXLXFile(),
|
||||
m_dmrXLXModule(),
|
||||
m_dmrXLXReflector(950U),
|
||||
m_dmrDstId(9990U),
|
||||
m_dmrPC(true),
|
||||
m_dmrNetworkAddress(),
|
||||
m_dmrNetworkPort(0U),
|
||||
m_dmrNetworkLocal(0U),
|
||||
m_dmrNetworkPassword(),
|
||||
m_dmrNetworkOptions(),
|
||||
m_dmrNetworkDebug(false),
|
||||
m_dmrNetworkJitterEnabled(true),
|
||||
m_dmrNetworkJitter(500U),
|
||||
m_dmrIdLookupFile(),
|
||||
m_dmrIdLookupTime(0U),
|
||||
m_m17DstId(0U),
|
||||
m_m17DstName(),
|
||||
m_m17DstAddress(),
|
||||
m_m17DstPort(0U),
|
||||
m_m17LocalAddress(),
|
||||
m_m17LocalPort(0U),
|
||||
m_m17GainAdjDb(),
|
||||
m_m17NetworkDebug(false),
|
||||
m_logDisplayLevel(0U),
|
||||
m_logFileLevel(0U),
|
||||
m_logFilePath(),
|
||||
m_logFileRoot()
|
||||
{
|
||||
}
|
||||
|
||||
CConf::~CConf()
|
||||
{
|
||||
}
|
||||
|
||||
bool CConf::read()
|
||||
{
|
||||
FILE* fp = ::fopen(m_file.c_str(), "rt");
|
||||
if (fp == NULL) {
|
||||
::fprintf(stderr, "Couldn't open the .ini file - %s\n", m_file.c_str());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SECTION section = SECTION_NONE;
|
||||
|
||||
char buffer[BUFFER_SIZE];
|
||||
while (::fgets(buffer, BUFFER_SIZE, fp) != NULL) {
|
||||
if (buffer[0U] == '#')
|
||||
continue;
|
||||
|
||||
if (buffer[0U] == '[') {
|
||||
if (::strncmp(buffer, "[Info]", 6U) == 0)
|
||||
section = SECTION_INFO;
|
||||
else if (::strncmp(buffer, "[M17 Network]", 13U) == 0)
|
||||
section = SECTION_M17_NETWORK;
|
||||
else if (::strncmp(buffer, "[DMR Network]", 13U) == 0)
|
||||
section = SECTION_DMR_NETWORK;
|
||||
else if (::strncmp(buffer, "[DMR Id Lookup]", 15U) == 0)
|
||||
section = SECTION_DMRID_LOOKUP;
|
||||
else if (::strncmp(buffer, "[Log]", 5U) == 0)
|
||||
section = SECTION_LOG;
|
||||
else
|
||||
section = SECTION_NONE;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
char* key = ::strtok(buffer, " \t=\r\n");
|
||||
if (key == NULL)
|
||||
continue;
|
||||
|
||||
char* value = ::strtok(NULL, "\r\n");
|
||||
if (value == NULL)
|
||||
continue;
|
||||
|
||||
// Remove quotes from the value
|
||||
size_t len = ::strlen(value);
|
||||
if (len > 1U && *value == '"' && value[len - 1U] == '"') {
|
||||
value[len - 1U] = '\0';
|
||||
value++;
|
||||
}
|
||||
::fprintf(stderr, "CConf key:val:section == %s:%s:%d\n", key, value, section);
|
||||
if (section == SECTION_INFO) {
|
||||
if (::strcmp(key, "TXFrequency") == 0)
|
||||
m_txFrequency = (unsigned int)::atoi(value);
|
||||
else if (::strcmp(key, "RXFrequency") == 0)
|
||||
m_rxFrequency = (unsigned int)::atoi(value);
|
||||
else if (::strcmp(key, "Power") == 0)
|
||||
m_power = (unsigned int)::atoi(value);
|
||||
else if (::strcmp(key, "Latitude") == 0)
|
||||
m_latitude = float(::atof(value));
|
||||
else if (::strcmp(key, "Longitude") == 0)
|
||||
m_longitude = float(::atof(value));
|
||||
else if (::strcmp(key, "Height") == 0)
|
||||
m_height = ::atoi(value);
|
||||
else if (::strcmp(key, "Location") == 0)
|
||||
m_location = value;
|
||||
else if (::strcmp(key, "Description") == 0)
|
||||
m_description = value;
|
||||
else if (::strcmp(key, "URL") == 0)
|
||||
m_url = value;
|
||||
} else if (section == SECTION_DMR_NETWORK) {
|
||||
if (::strcmp(key, "Id") == 0)
|
||||
m_dmrId = (unsigned int)::atoi(value);
|
||||
else if (::strcmp(key, "XLXFile") == 0)
|
||||
m_dmrXLXFile = value;
|
||||
else if (::strcmp(key, "XLXModule") == 0) {
|
||||
for (unsigned int i = 0U; value[i] != 0; i++)
|
||||
value[i] = ::toupper(value[i]);
|
||||
m_dmrXLXModule = value;
|
||||
}
|
||||
else if (::strcmp(key, "XLXReflector") == 0)
|
||||
m_dmrXLXReflector = (unsigned int)::atoi(value);
|
||||
else if (::strcmp(key, "StartupDstId") == 0)
|
||||
m_dmrDstId = (unsigned int)::atoi(value);
|
||||
else if (::strcmp(key, "StartupPC") == 0)
|
||||
m_dmrPC = ::atoi(value) == 1;
|
||||
else 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, "Options") == 0)
|
||||
m_dmrNetworkOptions = value;
|
||||
else if (::strcmp(key, "Debug") == 0)
|
||||
m_dmrNetworkDebug = ::atoi(value) == 1;
|
||||
else if (::strcmp(key, "JitterEnabled") == 0)
|
||||
m_dmrNetworkJitterEnabled = ::atoi(value) == 1;
|
||||
else if (::strcmp(key, "Jitter") == 0)
|
||||
m_dmrNetworkJitter = (unsigned int)::atoi(value);
|
||||
} else if (section == SECTION_M17_NETWORK) {
|
||||
if (::strcmp(key, "Callsign") == 0)
|
||||
m_callsign = value;
|
||||
else if (::strcmp(key, "StartupDstId") == 0)
|
||||
m_m17DstId = (unsigned int)::atoi(value);
|
||||
else if (::strcmp(key, "LocalAddress") == 0)
|
||||
m_m17LocalAddress = value;
|
||||
else if (::strcmp(key, "LocalPort") == 0)
|
||||
m_m17LocalPort = (unsigned int)::atoi(value);
|
||||
else if (::strcmp(key, "DstName") == 0)
|
||||
m_m17DstName = value;
|
||||
else if (::strcmp(key, "DstAddress") == 0)
|
||||
m_m17DstAddress = value;
|
||||
else if (::strcmp(key, "DstPort") == 0)
|
||||
m_m17DstPort = (unsigned int)::atoi(value);
|
||||
else if (::strcmp(key, "GainAdjustdB") == 0)
|
||||
m_m17GainAdjDb = value;
|
||||
else if (::strcmp(key, "Debug") == 0)
|
||||
m_m17NetworkDebug = ::atoi(value) == 1;
|
||||
}
|
||||
else if (section == SECTION_DMRID_LOOKUP) {
|
||||
if (::strcmp(key, "File") == 0)
|
||||
m_dmrIdLookupFile = value;
|
||||
else if (::strcmp(key, "Time") == 0)
|
||||
m_dmrIdLookupTime = (unsigned int)::atoi(value);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
||||
::fclose(fp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string CConf::getCallsign() const
|
||||
{
|
||||
return m_callsign;
|
||||
}
|
||||
|
||||
bool CConf::getDaemon() const
|
||||
{
|
||||
return m_daemon;
|
||||
}
|
||||
|
||||
unsigned int CConf::getRxFrequency() const
|
||||
{
|
||||
return m_rxFrequency;
|
||||
}
|
||||
|
||||
unsigned int CConf::getTxFrequency() const
|
||||
{
|
||||
return m_txFrequency;
|
||||
}
|
||||
|
||||
unsigned int CConf::getPower() const
|
||||
{
|
||||
return m_power;
|
||||
}
|
||||
|
||||
float CConf::getLatitude() const
|
||||
{
|
||||
return m_latitude;
|
||||
}
|
||||
|
||||
float CConf::getLongitude() const
|
||||
{
|
||||
return m_longitude;
|
||||
}
|
||||
|
||||
int CConf::getHeight() const
|
||||
{
|
||||
return m_height;
|
||||
}
|
||||
|
||||
std::string CConf::getLocation() const
|
||||
{
|
||||
return m_location;
|
||||
}
|
||||
|
||||
std::string CConf::getDescription() const
|
||||
{
|
||||
return m_description;
|
||||
}
|
||||
|
||||
std::string CConf::getURL() const
|
||||
{
|
||||
return m_url;
|
||||
}
|
||||
|
||||
unsigned int CConf::getDMRId() const
|
||||
{
|
||||
return m_dmrId;
|
||||
}
|
||||
|
||||
std::string CConf::getDMRXLXFile() const
|
||||
{
|
||||
return m_dmrXLXFile;
|
||||
}
|
||||
|
||||
std::string CConf::getDMRXLXModule() const
|
||||
{
|
||||
return m_dmrXLXModule;
|
||||
}
|
||||
|
||||
unsigned int CConf::getDMRXLXReflector() const
|
||||
{
|
||||
return m_dmrXLXReflector;
|
||||
}
|
||||
|
||||
unsigned int CConf::getDMRDstId() const
|
||||
{
|
||||
return m_dmrDstId;
|
||||
}
|
||||
|
||||
bool CConf::getDMRPC() const
|
||||
{
|
||||
return m_dmrPC;
|
||||
}
|
||||
|
||||
std::string CConf::getDMRNetworkAddress() const
|
||||
{
|
||||
return m_dmrNetworkAddress;
|
||||
}
|
||||
|
||||
unsigned int CConf::getDMRNetworkPort() const
|
||||
{
|
||||
return m_dmrNetworkPort;
|
||||
}
|
||||
|
||||
unsigned int CConf::getDMRNetworkLocal() const
|
||||
{
|
||||
return m_dmrNetworkLocal;
|
||||
}
|
||||
|
||||
std::string CConf::getDMRNetworkPassword() const
|
||||
{
|
||||
return m_dmrNetworkPassword;
|
||||
}
|
||||
|
||||
std::string CConf::getDMRNetworkOptions() const
|
||||
{
|
||||
return m_dmrNetworkOptions;
|
||||
}
|
||||
|
||||
bool CConf::getDMRNetworkDebug() const
|
||||
{
|
||||
return m_dmrNetworkDebug;
|
||||
}
|
||||
|
||||
bool CConf::getDMRNetworkJitterEnabled() const
|
||||
{
|
||||
return m_dmrNetworkJitterEnabled;
|
||||
}
|
||||
|
||||
unsigned int CConf::getDMRNetworkJitter() const
|
||||
{
|
||||
return m_dmrNetworkJitter;
|
||||
}
|
||||
|
||||
std::string CConf::getDMRIdLookupFile() const
|
||||
{
|
||||
return m_dmrIdLookupFile;
|
||||
}
|
||||
|
||||
unsigned int CConf::getDMRIdLookupTime() const
|
||||
{
|
||||
return m_dmrIdLookupTime;
|
||||
}
|
||||
|
||||
std::string CConf::getM17DstName() const
|
||||
{
|
||||
return m_m17DstName;
|
||||
}
|
||||
|
||||
std::string CConf::getM17DstAddress() const
|
||||
{
|
||||
return m_m17DstAddress;
|
||||
}
|
||||
|
||||
unsigned int CConf::getM17DstPort() const
|
||||
{
|
||||
return m_m17DstPort;
|
||||
}
|
||||
|
||||
std::string CConf::getM17LocalAddress() const
|
||||
{
|
||||
return m_m17LocalAddress;
|
||||
}
|
||||
|
||||
unsigned int CConf::getM17LocalPort() const
|
||||
{
|
||||
return m_m17LocalPort;
|
||||
}
|
||||
|
||||
std::string CConf::getM17GainAdjDb() const
|
||||
{
|
||||
return m_m17GainAdjDb;
|
||||
}
|
||||
|
||||
bool CConf::getM17NetworkDebug() const
|
||||
{
|
||||
return m_m17NetworkDebug;
|
||||
}
|
||||
|
||||
|
||||
unsigned int CConf::getLogDisplayLevel() const
|
||||
{
|
||||
return m_logDisplayLevel;
|
||||
}
|
||||
|
||||
unsigned int CConf::getLogFileLevel() const
|
||||
{
|
||||
return m_logFileLevel;
|
||||
}
|
||||
|
||||
std::string CConf::getLogFilePath() const
|
||||
{
|
||||
return m_logFilePath;
|
||||
}
|
||||
|
||||
std::string CConf::getLogFileRoot() const
|
||||
{
|
||||
return m_logFileRoot;
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||
*
|
||||
* 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(CONF_H)
|
||||
#define CONF_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class CConf
|
||||
{
|
||||
public:
|
||||
CConf(const std::string& file);
|
||||
~CConf();
|
||||
|
||||
bool read();
|
||||
|
||||
// The M17 Network section
|
||||
std::string getCallsign() const;
|
||||
bool getDaemon() const;
|
||||
unsigned int getM17DstId() const;
|
||||
std::string getM17DstName() const;
|
||||
std::string getM17DstAddress() const;
|
||||
unsigned int getM17DstPort() const;
|
||||
std::string getM17LocalAddress() const;
|
||||
unsigned int getM17LocalPort() const;
|
||||
std::string getM17GainAdjDb() const;
|
||||
bool getM17NetworkDebug() const;
|
||||
|
||||
// The Info section
|
||||
unsigned int getRxFrequency() const;
|
||||
unsigned int getTxFrequency() const;
|
||||
unsigned int getPower() const;
|
||||
float getLatitude() const;
|
||||
float getLongitude() const;
|
||||
int getHeight() const;
|
||||
std::string getLocation() const;
|
||||
std::string getDescription() const;
|
||||
std::string getURL() const;
|
||||
|
||||
// The DMR Network section
|
||||
unsigned int getDMRId() const;
|
||||
std::string getDMRXLXFile() const;
|
||||
std::string getDMRXLXModule() const;
|
||||
unsigned int getDMRXLXReflector() const;
|
||||
unsigned int getDMRDstId() const;
|
||||
bool getDMRPC() const;
|
||||
std::string getDMRNetworkAddress() const;
|
||||
unsigned int getDMRNetworkPort() const;
|
||||
unsigned int getDMRNetworkLocal() const;
|
||||
std::string getDMRNetworkPassword() const;
|
||||
std::string getDMRNetworkOptions() const;
|
||||
bool getDMRNetworkDebug() const;
|
||||
bool getDMRNetworkJitterEnabled() const;
|
||||
unsigned int getDMRNetworkJitter() const;
|
||||
|
||||
// The DMR Id section
|
||||
std::string getDMRIdLookupFile() const;
|
||||
unsigned int getDMRIdLookupTime() const;
|
||||
|
||||
// The Log section
|
||||
unsigned int getLogDisplayLevel() const;
|
||||
unsigned int getLogFileLevel() const;
|
||||
std::string getLogFilePath() const;
|
||||
std::string getLogFileRoot() const;
|
||||
|
||||
private:
|
||||
std::string m_file;
|
||||
std::string m_callsign;
|
||||
unsigned int m_tg;
|
||||
std::string m_dstAddress;
|
||||
unsigned int m_dstPort;
|
||||
std::string m_localAddress;
|
||||
unsigned int m_localPort;
|
||||
unsigned int m_defaultID;
|
||||
bool m_daemon;
|
||||
|
||||
unsigned int m_rxFrequency;
|
||||
unsigned int m_txFrequency;
|
||||
unsigned int m_power;
|
||||
float m_latitude;
|
||||
float m_longitude;
|
||||
int m_height;
|
||||
std::string m_location;
|
||||
std::string m_description;
|
||||
std::string m_url;
|
||||
|
||||
unsigned int m_dmrId;
|
||||
std::string m_dmrXLXFile;
|
||||
std::string m_dmrXLXModule;
|
||||
unsigned int m_dmrXLXReflector;
|
||||
unsigned int m_dmrDstId;
|
||||
bool m_dmrPC;
|
||||
std::string m_dmrNetworkAddress;
|
||||
unsigned int m_dmrNetworkPort;
|
||||
unsigned int m_dmrNetworkLocal;
|
||||
std::string m_dmrNetworkPassword;
|
||||
std::string m_dmrNetworkOptions;
|
||||
bool m_dmrNetworkDebug;
|
||||
bool m_dmrNetworkJitterEnabled;
|
||||
unsigned int m_dmrNetworkJitter;
|
||||
|
||||
std::string m_dmrIdLookupFile;
|
||||
unsigned int m_dmrIdLookupTime;
|
||||
|
||||
unsigned int m_m17DstId;
|
||||
std::string m_m17DstName;
|
||||
std::string m_m17DstAddress;
|
||||
unsigned int m_m17DstPort;
|
||||
std::string m_m17LocalAddress;
|
||||
unsigned int m_m17LocalPort;
|
||||
std::string m_m17GainAdjDb;
|
||||
bool m_m17NetworkDebug;
|
||||
|
||||
|
||||
unsigned int m_logDisplayLevel;
|
||||
unsigned int m_logFileLevel;
|
||||
std::string m_logFilePath;
|
||||
std::string m_logFileRoot;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
* Copyright (C) 2015,2016,2017 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; version 2 of the License.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "DMRData.h"
|
||||
#include "DMRDefines.h"
|
||||
#include "Utils.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
|
||||
|
||||
CDMRData::CDMRData(const CDMRData& data) :
|
||||
m_slotNo(data.m_slotNo),
|
||||
m_data(NULL),
|
||||
m_srcId(data.m_srcId),
|
||||
m_dstId(data.m_dstId),
|
||||
m_flco(data.m_flco),
|
||||
m_dataType(data.m_dataType),
|
||||
m_seqNo(data.m_seqNo),
|
||||
m_missing(data.m_missing),
|
||||
m_n(data.m_n),
|
||||
m_ber(data.m_ber),
|
||||
m_rssi(data.m_rssi),
|
||||
m_streamId(data.m_streamId)
|
||||
{
|
||||
m_data = new unsigned char[2U * DMR_FRAME_LENGTH_BYTES];
|
||||
::memcpy(m_data, data.m_data, 2U * DMR_FRAME_LENGTH_BYTES);
|
||||
}
|
||||
|
||||
CDMRData::CDMRData() :
|
||||
m_slotNo(1U),
|
||||
m_data(NULL),
|
||||
m_srcId(0U),
|
||||
m_dstId(0U),
|
||||
m_flco(FLCO_GROUP),
|
||||
m_dataType(0U),
|
||||
m_seqNo(0U),
|
||||
m_missing(false),
|
||||
m_n(0U),
|
||||
m_ber(0U),
|
||||
m_rssi(0U),
|
||||
m_streamId(0U)
|
||||
{
|
||||
m_data = new unsigned char[2U * DMR_FRAME_LENGTH_BYTES];
|
||||
}
|
||||
|
||||
CDMRData::~CDMRData()
|
||||
{
|
||||
delete[] m_data;
|
||||
}
|
||||
|
||||
CDMRData& CDMRData::operator=(const CDMRData& data)
|
||||
{
|
||||
if (this != &data) {
|
||||
::memcpy(m_data, data.m_data, DMR_FRAME_LENGTH_BYTES);
|
||||
|
||||
m_slotNo = data.m_slotNo;
|
||||
m_srcId = data.m_srcId;
|
||||
m_dstId = data.m_dstId;
|
||||
m_flco = data.m_flco;
|
||||
m_dataType = data.m_dataType;
|
||||
m_seqNo = data.m_seqNo;
|
||||
m_missing = data.m_missing;
|
||||
m_n = data.m_n;
|
||||
m_ber = data.m_ber;
|
||||
m_rssi = data.m_rssi;
|
||||
m_streamId = data.m_streamId;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
unsigned int CDMRData::getSlotNo() const
|
||||
{
|
||||
return m_slotNo;
|
||||
}
|
||||
|
||||
void CDMRData::setSlotNo(unsigned int slotNo)
|
||||
{
|
||||
assert(slotNo == 1U || slotNo == 2U);
|
||||
|
||||
m_slotNo = slotNo;
|
||||
}
|
||||
|
||||
unsigned char CDMRData::getDataType() const
|
||||
{
|
||||
return m_dataType;
|
||||
}
|
||||
|
||||
void CDMRData::setDataType(unsigned char dataType)
|
||||
{
|
||||
m_dataType = dataType;
|
||||
}
|
||||
|
||||
unsigned int CDMRData::getSrcId() const
|
||||
{
|
||||
return m_srcId;
|
||||
}
|
||||
|
||||
void CDMRData::setSrcId(unsigned int id)
|
||||
{
|
||||
m_srcId = id;
|
||||
}
|
||||
|
||||
unsigned int CDMRData::getDstId() const
|
||||
{
|
||||
return m_dstId;
|
||||
}
|
||||
|
||||
void CDMRData::setDstId(unsigned int id)
|
||||
{
|
||||
m_dstId = id;
|
||||
}
|
||||
|
||||
FLCO CDMRData::getFLCO() const
|
||||
{
|
||||
return m_flco;
|
||||
}
|
||||
|
||||
void CDMRData::setFLCO(FLCO flco)
|
||||
{
|
||||
m_flco = flco;
|
||||
}
|
||||
|
||||
unsigned char CDMRData::getSeqNo() const
|
||||
{
|
||||
return m_seqNo;
|
||||
}
|
||||
|
||||
void CDMRData::setSeqNo(unsigned char seqNo)
|
||||
{
|
||||
m_seqNo = seqNo;
|
||||
}
|
||||
|
||||
bool CDMRData::isMissing() const
|
||||
{
|
||||
return m_missing;
|
||||
}
|
||||
|
||||
void CDMRData::setMissing(bool missing)
|
||||
{
|
||||
m_missing = missing;
|
||||
}
|
||||
|
||||
unsigned char CDMRData::getN() const
|
||||
{
|
||||
return m_n;
|
||||
}
|
||||
|
||||
void CDMRData::setN(unsigned char n)
|
||||
{
|
||||
m_n = n;
|
||||
}
|
||||
|
||||
unsigned char CDMRData::getBER() const
|
||||
{
|
||||
return m_ber;
|
||||
}
|
||||
|
||||
void CDMRData::setBER(unsigned char ber)
|
||||
{
|
||||
m_ber = ber;
|
||||
}
|
||||
|
||||
unsigned char CDMRData::getRSSI() const
|
||||
{
|
||||
return m_rssi;
|
||||
}
|
||||
|
||||
void CDMRData::setRSSI(unsigned char rssi)
|
||||
{
|
||||
m_rssi = rssi;
|
||||
}
|
||||
|
||||
unsigned int CDMRData::getData(unsigned char* buffer) const
|
||||
{
|
||||
assert(buffer != NULL);
|
||||
|
||||
::memcpy(buffer, m_data, DMR_FRAME_LENGTH_BYTES);
|
||||
|
||||
return DMR_FRAME_LENGTH_BYTES;
|
||||
}
|
||||
|
||||
void CDMRData::setData(const unsigned char* buffer)
|
||||
{
|
||||
assert(buffer != NULL);
|
||||
|
||||
::memcpy(m_data, buffer, DMR_FRAME_LENGTH_BYTES);
|
||||
}
|
||||
|
||||
unsigned int CDMRData::getStreamId() const
|
||||
{
|
||||
return m_streamId;
|
||||
}
|
||||
|
||||
void CDMRData::setStreamId(unsigned int id)
|
||||
{
|
||||
m_streamId = id;
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* 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; version 2 of the License.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef DMRData_H
|
||||
#define DMRData_H
|
||||
|
||||
#include "DMRDefines.h"
|
||||
|
||||
class CDMRData {
|
||||
public:
|
||||
CDMRData(const CDMRData& data);
|
||||
CDMRData();
|
||||
~CDMRData();
|
||||
|
||||
CDMRData& operator=(const CDMRData& data);
|
||||
|
||||
unsigned int getSlotNo() const;
|
||||
void setSlotNo(unsigned int slotNo);
|
||||
|
||||
unsigned int getSrcId() const;
|
||||
void setSrcId(unsigned int id);
|
||||
|
||||
unsigned int getDstId() const;
|
||||
void setDstId(unsigned int id);
|
||||
|
||||
FLCO getFLCO() const;
|
||||
void setFLCO(FLCO flco);
|
||||
|
||||
unsigned char getN() const;
|
||||
void setN(unsigned char n);
|
||||
|
||||
unsigned char getSeqNo() const;
|
||||
void setSeqNo(unsigned char seqNo);
|
||||
|
||||
unsigned char getDataType() const;
|
||||
void setDataType(unsigned char dataType);
|
||||
|
||||
bool isMissing() const;
|
||||
void setMissing(bool missing);
|
||||
|
||||
unsigned char getBER() const;
|
||||
void setBER(unsigned char ber);
|
||||
|
||||
unsigned char getRSSI() const;
|
||||
void setRSSI(unsigned char rssi);
|
||||
|
||||
void setData(const unsigned char* buffer);
|
||||
unsigned int getData(unsigned char* buffer) const;
|
||||
|
||||
void setStreamId(unsigned int id);
|
||||
unsigned int getStreamId() const;
|
||||
|
||||
private:
|
||||
unsigned int m_slotNo;
|
||||
unsigned char* m_data;
|
||||
unsigned int m_srcId;
|
||||
unsigned int m_dstId;
|
||||
FLCO m_flco;
|
||||
unsigned char m_dataType;
|
||||
unsigned char m_seqNo;
|
||||
bool m_missing;
|
||||
unsigned char m_n;
|
||||
unsigned char m_ber;
|
||||
unsigned char m_rssi;
|
||||
unsigned int m_streamId;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* 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(DMRDefines_H)
|
||||
#define DMRDefines_H
|
||||
|
||||
#include "Defines.h" // For TAG_DATA
|
||||
|
||||
const unsigned int DMR_FRAME_LENGTH_BITS = 264U;
|
||||
const unsigned int DMR_FRAME_LENGTH_BYTES = 33U;
|
||||
|
||||
const unsigned int DMR_SYNC_LENGTH_BITS = 48U;
|
||||
const unsigned int DMR_SYNC_LENGTH_BYTES = 6U;
|
||||
|
||||
const unsigned int DMR_EMB_LENGTH_BITS = 8U;
|
||||
const unsigned int DMR_EMB_LENGTH_BYTES = 1U;
|
||||
|
||||
const unsigned int DMR_SLOT_TYPE_LENGTH_BITS = 8U;
|
||||
const unsigned int DMR_SLOT_TYPE_LENGTH_BYTES = 1U;
|
||||
|
||||
const unsigned int DMR_EMBEDDED_SIGNALLING_LENGTH_BITS = 32U;
|
||||
const unsigned int DMR_EMBEDDED_SIGNALLING_LENGTH_BYTES = 4U;
|
||||
|
||||
const unsigned int DMR_AMBE_LENGTH_BITS = 108U * 2U;
|
||||
const unsigned int DMR_AMBE_LENGTH_BYTES = 27U;
|
||||
|
||||
const unsigned char BS_SOURCED_AUDIO_SYNC[] = {0x07U, 0x55U, 0xFDU, 0x7DU, 0xF7U, 0x5FU, 0x70U};
|
||||
const unsigned char BS_SOURCED_DATA_SYNC[] = {0x0DU, 0xFFU, 0x57U, 0xD7U, 0x5DU, 0xF5U, 0xD0U};
|
||||
|
||||
const unsigned char MS_SOURCED_AUDIO_SYNC[] = {0x07U, 0xF7U, 0xD5U, 0xDDU, 0x57U, 0xDFU, 0xD0U};
|
||||
const unsigned char MS_SOURCED_DATA_SYNC[] = {0x0DU, 0x5DU, 0x7FU, 0x77U, 0xFDU, 0x75U, 0x70U};
|
||||
|
||||
const unsigned char DIRECT_SLOT1_AUDIO_SYNC[] = {0x05U, 0xD5U, 0x77U, 0xF7U, 0x75U, 0x7FU, 0xF0U};
|
||||
const unsigned char DIRECT_SLOT1_DATA_SYNC[] = {0x0FU, 0x7FU, 0xDDU, 0x5DU, 0xDFU, 0xD5U, 0x50U};
|
||||
|
||||
const unsigned char DIRECT_SLOT2_AUDIO_SYNC[] = {0x07U, 0xDFU, 0xFDU, 0x5FU, 0x55U, 0xD5U, 0xF0U};
|
||||
const unsigned char DIRECT_SLOT2_DATA_SYNC[] = {0x0DU, 0x75U, 0x57U, 0xF5U, 0xFFU, 0x7FU, 0x50U};
|
||||
|
||||
const unsigned char SYNC_MASK[] = {0x0FU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xF0U};
|
||||
|
||||
// The PR FILL and Data Sync pattern.
|
||||
const unsigned char DMR_IDLE_DATA[] = {TAG_DATA, 0x00U,
|
||||
0x53U, 0xC2U, 0x5EU, 0xABU, 0xA8U, 0x67U, 0x1DU, 0xC7U, 0x38U, 0x3BU, 0xD9U,
|
||||
0x36U, 0x00U, 0x0DU, 0xFFU, 0x57U, 0xD7U, 0x5DU, 0xF5U, 0xD0U, 0x03U, 0xF6U,
|
||||
0xE4U, 0x65U, 0x17U, 0x1BU, 0x48U, 0xCAU, 0x6DU, 0x4FU, 0xC6U, 0x10U, 0xB4U};
|
||||
|
||||
// A silence frame only
|
||||
const unsigned char DMR_SILENCE_DATA[] = {0xB9U, 0xE8U, 0x81U, 0x52U, 0x61U, 0x73U, 0x00U, 0x2AU, 0x6BU, 0xB9U, 0xE8U,
|
||||
0x81U, 0x52U, 0x60U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x01U, 0x73U, 0x00U,
|
||||
0x2AU, 0x6BU, 0xB9U, 0xE8U, 0x81U, 0x52U, 0x61U, 0x73U, 0x00U, 0x2AU, 0x6BU};
|
||||
|
||||
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;
|
||||
const unsigned char DT_TERMINATOR_WITH_LC = 0x02U;
|
||||
const unsigned char DT_CSBK = 0x03U;
|
||||
const unsigned char DT_DATA_HEADER = 0x06U;
|
||||
const unsigned char DT_RATE_12_DATA = 0x07U;
|
||||
const unsigned char DT_RATE_34_DATA = 0x08U;
|
||||
const unsigned char DT_IDLE = 0x09U;
|
||||
const unsigned char DT_RATE_1_DATA = 0x0AU;
|
||||
|
||||
// Dummy values
|
||||
const unsigned char DT_VOICE_SYNC = 0xF0U;
|
||||
const unsigned char DT_VOICE = 0xF1U;
|
||||
|
||||
const unsigned char DMR_IDLE_RX = 0x80U;
|
||||
const unsigned char DMR_SYNC_DATA = 0x40U;
|
||||
const unsigned char DMR_SYNC_AUDIO = 0x20U;
|
||||
|
||||
const unsigned char DMR_SLOT1 = 0x00U;
|
||||
const unsigned char DMR_SLOT2 = 0x80U;
|
||||
|
||||
const unsigned char DPF_UDT = 0x00U;
|
||||
const unsigned char DPF_RESPONSE = 0x01U;
|
||||
const unsigned char DPF_UNCONFIRMED_DATA = 0x02U;
|
||||
const unsigned char DPF_CONFIRMED_DATA = 0x03U;
|
||||
const unsigned char DPF_DEFINED_SHORT = 0x0DU;
|
||||
const unsigned char DPF_DEFINED_RAW = 0x0EU;
|
||||
const unsigned char DPF_PROPRIETARY = 0x0FU;
|
||||
|
||||
const unsigned char FID_ETSI = 0U;
|
||||
const unsigned char FID_DMRA = 16U;
|
||||
|
||||
enum FLCO {
|
||||
FLCO_GROUP = 0,
|
||||
FLCO_USER_USER = 3,
|
||||
FLCO_TALKER_ALIAS_HEADER = 4,
|
||||
FLCO_TALKER_ALIAS_BLOCK1 = 5,
|
||||
FLCO_TALKER_ALIAS_BLOCK2 = 6,
|
||||
FLCO_TALKER_ALIAS_BLOCK3 = 7,
|
||||
FLCO_GPS_INFO = 8
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* 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 "DMREMB.h"
|
||||
|
||||
#include "QR1676.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
CDMREMB::CDMREMB() :
|
||||
m_colorCode(0U),
|
||||
m_PI(false),
|
||||
m_LCSS(0U)
|
||||
{
|
||||
}
|
||||
|
||||
CDMREMB::~CDMREMB()
|
||||
{
|
||||
}
|
||||
|
||||
void CDMREMB::putData(const unsigned char* data)
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
unsigned char DMREMB[2U];
|
||||
DMREMB[0U] = (data[13U] << 4) & 0xF0U;
|
||||
DMREMB[0U] |= (data[14U] >> 4) & 0x0FU;
|
||||
DMREMB[1U] = (data[18U] << 4) & 0xF0U;
|
||||
DMREMB[1U] |= (data[19U] >> 4) & 0x0FU;
|
||||
|
||||
CQR1676::decode(DMREMB);
|
||||
|
||||
m_colorCode = (DMREMB[0U] >> 4) & 0x0FU;
|
||||
m_PI = (DMREMB[0U] & 0x08U) == 0x08U;
|
||||
m_LCSS = (DMREMB[0U] >> 1) & 0x03U;
|
||||
}
|
||||
|
||||
void CDMREMB::getData(unsigned char* data) const
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
unsigned char DMREMB[2U];
|
||||
DMREMB[0U] = (m_colorCode << 4) & 0xF0U;
|
||||
DMREMB[0U] |= m_PI ? 0x08U : 0x00U;
|
||||
DMREMB[0U] |= (m_LCSS << 1) & 0x06U;
|
||||
DMREMB[1U] = 0x00U;
|
||||
|
||||
CQR1676::encode(DMREMB);
|
||||
|
||||
data[13U] = (data[13U] & 0xF0U) | ((DMREMB[0U] >> 4U) & 0x0FU);
|
||||
data[14U] = (data[14U] & 0x0FU) | ((DMREMB[0U] << 4U) & 0xF0U);
|
||||
data[18U] = (data[18U] & 0xF0U) | ((DMREMB[1U] >> 4U) & 0x0FU);
|
||||
data[19U] = (data[19U] & 0x0FU) | ((DMREMB[1U] << 4U) & 0xF0U);
|
||||
}
|
||||
|
||||
unsigned char CDMREMB::getColorCode() const
|
||||
{
|
||||
return m_colorCode;
|
||||
}
|
||||
|
||||
void CDMREMB::setColorCode(unsigned char code)
|
||||
{
|
||||
m_colorCode = code;
|
||||
}
|
||||
|
||||
bool CDMREMB::getPI() const
|
||||
{
|
||||
return m_PI;
|
||||
}
|
||||
|
||||
void CDMREMB::setPI(bool pi)
|
||||
{
|
||||
m_PI = pi;
|
||||
}
|
||||
|
||||
unsigned char CDMREMB::getLCSS() const
|
||||
{
|
||||
return m_LCSS;
|
||||
}
|
||||
|
||||
void CDMREMB::setLCSS(unsigned char lcss)
|
||||
{
|
||||
m_LCSS = lcss;
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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(DMREMB_H)
|
||||
#define DMREMB_H
|
||||
|
||||
class CDMREMB
|
||||
{
|
||||
public:
|
||||
CDMREMB();
|
||||
~CDMREMB();
|
||||
|
||||
void putData(const unsigned char* data);
|
||||
void getData(unsigned char* data) const;
|
||||
|
||||
unsigned char getColorCode() const;
|
||||
void setColorCode(unsigned char code);
|
||||
|
||||
bool getPI() const;
|
||||
void setPI(bool pi);
|
||||
|
||||
unsigned char getLCSS() const;
|
||||
void setLCSS(unsigned char lcss);
|
||||
|
||||
private:
|
||||
unsigned char m_colorCode;
|
||||
bool m_PI;
|
||||
unsigned char m_LCSS;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -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 <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
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;
|
||||
}
|
|
@ -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
|
|
@ -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 <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
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);
|
||||
}
|
|
@ -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
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -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 <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
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;
|
||||
}
|
|
@ -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
|
||||
|
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* Copyright (C) 2016,2017 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||
*
|
||||
* 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 "DMRLookup.h"
|
||||
#include "Timer.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cctype>
|
||||
|
||||
CDMRLookup::CDMRLookup(const std::string& filename, unsigned int reloadTime) :
|
||||
CThread(),
|
||||
m_filename(filename),
|
||||
m_reloadTime(reloadTime),
|
||||
m_table(),
|
||||
m_cstable(),
|
||||
m_mutex(),
|
||||
m_stop(false)
|
||||
{
|
||||
}
|
||||
|
||||
CDMRLookup::~CDMRLookup()
|
||||
{
|
||||
}
|
||||
|
||||
bool CDMRLookup::read()
|
||||
{
|
||||
bool ret = load();
|
||||
|
||||
if (m_reloadTime > 0U)
|
||||
run();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CDMRLookup::entry()
|
||||
{
|
||||
LogInfo("Started the DMR Id lookup reload thread");
|
||||
|
||||
CTimer timer(1U, 3600U * m_reloadTime);
|
||||
timer.start();
|
||||
|
||||
while (!m_stop) {
|
||||
sleep(1000U);
|
||||
|
||||
timer.clock();
|
||||
if (timer.hasExpired()) {
|
||||
load();
|
||||
timer.start();
|
||||
}
|
||||
}
|
||||
|
||||
LogInfo("Stopped the DMR Id lookup reload thread");
|
||||
}
|
||||
|
||||
void CDMRLookup::stop()
|
||||
{
|
||||
if (m_reloadTime == 0U) {
|
||||
delete this;
|
||||
return;
|
||||
}
|
||||
|
||||
m_stop = true;
|
||||
|
||||
wait();
|
||||
}
|
||||
|
||||
std::string CDMRLookup::findCS(unsigned int id)
|
||||
{
|
||||
std::string callsign;
|
||||
|
||||
if (id == 0xFFFFFFU)
|
||||
return std::string("ALL");
|
||||
|
||||
m_mutex.lock();
|
||||
|
||||
try {
|
||||
callsign = m_table.at(id);
|
||||
} catch (...) {
|
||||
char text[10U];
|
||||
::sprintf(text, "%u", id);
|
||||
callsign = std::string(text);
|
||||
}
|
||||
|
||||
m_mutex.unlock();
|
||||
|
||||
return callsign;
|
||||
}
|
||||
|
||||
unsigned int CDMRLookup::findID(std::string cs)
|
||||
{
|
||||
unsigned int dmrID;
|
||||
|
||||
m_mutex.lock();
|
||||
|
||||
try {
|
||||
dmrID = m_cstable.at(cs);
|
||||
} catch (...) {
|
||||
dmrID = 0U;
|
||||
}
|
||||
|
||||
m_mutex.unlock();
|
||||
|
||||
return dmrID;
|
||||
}
|
||||
|
||||
bool CDMRLookup::exists(unsigned int id)
|
||||
{
|
||||
m_mutex.lock();
|
||||
|
||||
bool found = m_table.count(id) == 1U;
|
||||
|
||||
m_mutex.unlock();
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
bool CDMRLookup::load()
|
||||
{
|
||||
FILE* fp = ::fopen(m_filename.c_str(), "rt");
|
||||
if (fp == NULL) {
|
||||
LogWarning("Cannot open the DMR Id lookup file - %s", m_filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
m_mutex.lock();
|
||||
|
||||
// Remove the old entries
|
||||
m_table.clear();
|
||||
m_cstable.clear();
|
||||
|
||||
char buffer[100U];
|
||||
while (::fgets(buffer, 100U, fp) != NULL) {
|
||||
if (buffer[0U] == '#')
|
||||
continue;
|
||||
|
||||
char* p1 = ::strtok(buffer, " \t\r\n");
|
||||
char* p2 = ::strtok(NULL, " \t\r\n");
|
||||
|
||||
if (p1 != NULL && p2 != NULL) {
|
||||
unsigned int id = (unsigned int)::atoi(p1);
|
||||
for (char* p = p2; *p != 0x00U; p++)
|
||||
*p = ::toupper(*p);
|
||||
|
||||
m_table[id] = std::string(p2);
|
||||
m_cstable[p2] = id;
|
||||
}
|
||||
}
|
||||
|
||||
m_mutex.unlock();
|
||||
|
||||
::fclose(fp);
|
||||
|
||||
size_t size = m_table.size();
|
||||
if (size == 0U)
|
||||
return false;
|
||||
|
||||
LogInfo("Loaded %u Ids to the DMR callsign lookup table", size);
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (C) 2016,2017 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||
*
|
||||
* 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 DMRLookup_H
|
||||
#define DMRLookup_H
|
||||
|
||||
#include "Thread.h"
|
||||
#include "Mutex.h"
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
class CDMRLookup : public CThread {
|
||||
public:
|
||||
CDMRLookup(const std::string& filename, unsigned int reloadTime);
|
||||
virtual ~CDMRLookup();
|
||||
|
||||
bool read();
|
||||
|
||||
virtual void entry();
|
||||
|
||||
std::string findCS(unsigned int id);
|
||||
unsigned int findID(std::string cs);
|
||||
|
||||
bool exists(unsigned int id);
|
||||
|
||||
void stop();
|
||||
|
||||
private:
|
||||
std::string m_filename;
|
||||
unsigned int m_reloadTime;
|
||||
std::unordered_map<unsigned int, std::string> m_table;
|
||||
std::unordered_map<std::string, unsigned int> m_cstable;
|
||||
CMutex m_mutex;
|
||||
bool m_stop;
|
||||
|
||||
bool load();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,673 @@
|
|||
/*
|
||||
* Copyright (C) 2015,2016,2017,2018 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 "DMRNetwork.h"
|
||||
|
||||
#include "StopWatch.h"
|
||||
#include "SHA256.h"
|
||||
#include "Utils.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
const unsigned int BUFFER_LENGTH = 500U;
|
||||
|
||||
const unsigned int HOMEBREW_DATA_PACKET_LENGTH = 55U;
|
||||
|
||||
CDMRNetwork::CDMRNetwork(const std::string& address, unsigned int port, unsigned int local, unsigned int id, const std::string& password, bool duplex, const char* version, bool debug, bool slot1, bool slot2, HW_TYPE hwType, unsigned int jitter) :
|
||||
m_address(),
|
||||
m_port(port),
|
||||
m_id(NULL),
|
||||
m_password(password),
|
||||
m_duplex(duplex),
|
||||
m_version(version),
|
||||
m_debug(debug),
|
||||
m_socket(local),
|
||||
m_enabled(false),
|
||||
m_slot1(slot1),
|
||||
m_slot2(slot2),
|
||||
m_delayBuffers(NULL),
|
||||
m_hwType(hwType),
|
||||
m_status(WAITING_CONNECT),
|
||||
m_retryTimer(1000U, 10U),
|
||||
m_timeoutTimer(1000U, 60U),
|
||||
m_buffer(NULL),
|
||||
m_salt(NULL),
|
||||
m_streamId(NULL),
|
||||
m_options(),
|
||||
m_callsign(),
|
||||
m_rxFrequency(0U),
|
||||
m_txFrequency(0U),
|
||||
m_power(0U),
|
||||
m_colorCode(0U),
|
||||
m_latitude(0.0F),
|
||||
m_longitude(0.0F),
|
||||
m_height(0),
|
||||
m_location(),
|
||||
m_description(),
|
||||
m_url(),
|
||||
m_beacon(false)
|
||||
{
|
||||
assert(!address.empty());
|
||||
assert(port > 0U);
|
||||
assert(id > 1000U);
|
||||
assert(!password.empty());
|
||||
assert(jitter > 0U);
|
||||
|
||||
m_address = CUDPSocket::lookup(address);
|
||||
|
||||
m_buffer = new unsigned char[BUFFER_LENGTH];
|
||||
m_salt = new unsigned char[sizeof(uint32_t)];
|
||||
m_id = new uint8_t[4U];
|
||||
m_streamId = new uint32_t[2U];
|
||||
|
||||
m_delayBuffers = new CDelayBuffer*[3U];
|
||||
|
||||
m_delayBuffers[1U] = new CDelayBuffer("DMR Slot 1", HOMEBREW_DATA_PACKET_LENGTH, DMR_SLOT_TIME, jitter, debug);
|
||||
m_delayBuffers[2U] = new CDelayBuffer("DMR Slot 2", HOMEBREW_DATA_PACKET_LENGTH, DMR_SLOT_TIME, jitter, debug);
|
||||
|
||||
m_id[0U] = id >> 24;
|
||||
m_id[1U] = id >> 16;
|
||||
m_id[2U] = id >> 8;
|
||||
m_id[3U] = id >> 0;
|
||||
|
||||
CStopWatch stopWatch;
|
||||
::srand(stopWatch.start());
|
||||
|
||||
m_streamId[0U] = ::rand() + 1U;
|
||||
m_streamId[1U] = ::rand() + 1U;
|
||||
}
|
||||
|
||||
CDMRNetwork::~CDMRNetwork()
|
||||
{
|
||||
delete m_delayBuffers[1U];
|
||||
delete m_delayBuffers[2U];
|
||||
|
||||
delete[] m_buffer;
|
||||
delete[] m_salt;
|
||||
delete[] m_streamId;
|
||||
delete[] m_id;
|
||||
|
||||
delete[] m_delayBuffers;
|
||||
}
|
||||
|
||||
void CDMRNetwork::setOptions(const std::string& options)
|
||||
{
|
||||
m_options = options;
|
||||
}
|
||||
|
||||
void CDMRNetwork::setConfig(const std::string& callsign, unsigned int rxFrequency, unsigned int txFrequency, unsigned int power, unsigned int colorCode, float latitude, float longitude, int height, const std::string& location, const std::string& description, const std::string& url)
|
||||
{
|
||||
m_callsign = callsign;
|
||||
m_rxFrequency = rxFrequency;
|
||||
m_txFrequency = txFrequency;
|
||||
m_power = power;
|
||||
m_colorCode = colorCode;
|
||||
m_latitude = latitude;
|
||||
m_longitude = longitude;
|
||||
m_height = height;
|
||||
m_location = location;
|
||||
m_description = description;
|
||||
m_url = url;
|
||||
}
|
||||
|
||||
bool CDMRNetwork::open()
|
||||
{
|
||||
LogMessage("DMR, Opening DMR Network");
|
||||
|
||||
m_status = WAITING_CONNECT;
|
||||
m_timeoutTimer.stop();
|
||||
m_retryTimer.start();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CDMRNetwork::enable(bool enabled)
|
||||
{
|
||||
m_enabled = enabled;
|
||||
}
|
||||
|
||||
bool CDMRNetwork::read(CDMRData& data)
|
||||
{
|
||||
if (m_status != RUNNING)
|
||||
return false;
|
||||
|
||||
for (unsigned int slotNo = 1U; slotNo <= 2U; slotNo++) {
|
||||
unsigned int length = 0U;
|
||||
B_STATUS status = BS_NO_DATA;
|
||||
|
||||
status = m_delayBuffers[slotNo]->getData(m_buffer, length);
|
||||
|
||||
if (status != BS_NO_DATA) {
|
||||
unsigned char seqNo = m_buffer[4U];
|
||||
|
||||
unsigned int srcId = (m_buffer[5U] << 16) | (m_buffer[6U] << 8) | (m_buffer[7U] << 0);
|
||||
|
||||
unsigned int dstId = (m_buffer[8U] << 16) | (m_buffer[9U] << 8) | (m_buffer[10U] << 0);
|
||||
|
||||
FLCO flco = (m_buffer[15U] & 0x40U) == 0x40U ? FLCO_USER_USER : FLCO_GROUP;
|
||||
|
||||
data.setSeqNo(seqNo);
|
||||
data.setSlotNo(slotNo);
|
||||
data.setSrcId(srcId);
|
||||
data.setDstId(dstId);
|
||||
data.setFLCO(flco);
|
||||
data.setMissing(status == BS_MISSING);
|
||||
|
||||
bool dataSync = (m_buffer[15U] & 0x20U) == 0x20U;
|
||||
bool voiceSync = (m_buffer[15U] & 0x10U) == 0x10U;
|
||||
|
||||
if (dataSync) {
|
||||
unsigned char dataType = m_buffer[15U] & 0x0FU;
|
||||
data.setData(m_buffer + 20U);
|
||||
data.setDataType(dataType);
|
||||
data.setN(0U);
|
||||
} else if (voiceSync) {
|
||||
data.setData(m_buffer + 20U);
|
||||
data.setDataType(DT_VOICE_SYNC);
|
||||
data.setN(0U);
|
||||
} else {
|
||||
unsigned char n = m_buffer[15U] & 0x0FU;
|
||||
data.setData(m_buffer + 20U);
|
||||
data.setDataType(DT_VOICE);
|
||||
data.setN(n);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CDMRNetwork::write(const CDMRData& data)
|
||||
{
|
||||
if (m_status != RUNNING)
|
||||
return false;
|
||||
|
||||
unsigned char buffer[HOMEBREW_DATA_PACKET_LENGTH];
|
||||
::memset(buffer, 0x00U, HOMEBREW_DATA_PACKET_LENGTH);
|
||||
|
||||
buffer[0U] = 'D';
|
||||
buffer[1U] = 'M';
|
||||
buffer[2U] = 'R';
|
||||
buffer[3U] = 'D';
|
||||
|
||||
unsigned int srcId = data.getSrcId();
|
||||
buffer[5U] = srcId >> 16;
|
||||
buffer[6U] = srcId >> 8;
|
||||
buffer[7U] = srcId >> 0;
|
||||
|
||||
unsigned int dstId = data.getDstId();
|
||||
buffer[8U] = dstId >> 16;
|
||||
buffer[9U] = dstId >> 8;
|
||||
buffer[10U] = dstId >> 0;
|
||||
|
||||
::memcpy(buffer + 11U, m_id, 4U);
|
||||
|
||||
unsigned int slotNo = data.getSlotNo();
|
||||
|
||||
// Individual slot disabling
|
||||
if (slotNo == 1U && !m_slot1)
|
||||
return false;
|
||||
if (slotNo == 2U && !m_slot2)
|
||||
return false;
|
||||
|
||||
buffer[15U] = slotNo == 1U ? 0x00U : 0x80U;
|
||||
|
||||
FLCO flco = data.getFLCO();
|
||||
buffer[15U] |= flco == FLCO_GROUP ? 0x00U : 0x40U;
|
||||
|
||||
unsigned int slotIndex = slotNo - 1U;
|
||||
|
||||
unsigned int count = 1U;
|
||||
|
||||
unsigned char dataType = data.getDataType();
|
||||
if (dataType == DT_VOICE_SYNC) {
|
||||
buffer[15U] |= 0x10U;
|
||||
} else if (dataType == DT_VOICE) {
|
||||
buffer[15U] |= data.getN();
|
||||
} else {
|
||||
if (dataType == DT_VOICE_LC_HEADER)
|
||||
count = 2U;
|
||||
|
||||
buffer[15U] |= (0x20U | dataType);
|
||||
}
|
||||
|
||||
buffer[4U] = data.getSeqNo();
|
||||
|
||||
::memcpy(buffer + 16U, m_streamId + slotIndex, 4U);
|
||||
|
||||
data.getData(buffer + 20U);
|
||||
|
||||
buffer[53U] = data.getBER();
|
||||
|
||||
buffer[54U] = data.getRSSI();
|
||||
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "Network Transmitted", buffer, HOMEBREW_DATA_PACKET_LENGTH);
|
||||
|
||||
for (unsigned int i = 0U; i < count; i++)
|
||||
write(buffer, HOMEBREW_DATA_PACKET_LENGTH);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDMRNetwork::writePosition(unsigned int id, const unsigned char* data)
|
||||
{
|
||||
if (m_status != RUNNING)
|
||||
return false;
|
||||
|
||||
unsigned char buffer[20U];
|
||||
|
||||
::memcpy(buffer + 0U, "DMRG", 4U);
|
||||
|
||||
::memcpy(buffer + 4U, m_id, 4U);
|
||||
|
||||
buffer[8U] = id >> 16;
|
||||
buffer[9U] = id >> 8;
|
||||
buffer[10U] = id >> 0;
|
||||
|
||||
::memcpy(buffer + 11U, data + 2U, 7U);
|
||||
|
||||
return write(buffer, 18U);
|
||||
}
|
||||
|
||||
bool CDMRNetwork::writeTalkerAlias(unsigned int id, unsigned char type, const unsigned char* data)
|
||||
{
|
||||
if (m_status != RUNNING)
|
||||
return false;
|
||||
|
||||
unsigned char buffer[20U];
|
||||
|
||||
::memcpy(buffer + 0U, "DMRA", 4U);
|
||||
|
||||
::memcpy(buffer + 4U, m_id, 4U);
|
||||
|
||||
buffer[8U] = id >> 16;
|
||||
buffer[9U] = id >> 8;
|
||||
buffer[10U] = id >> 0;
|
||||
|
||||
buffer[11U] = type;
|
||||
|
||||
::memcpy(buffer + 12U, data + 2U, 7U);
|
||||
|
||||
return write(buffer, 19U);
|
||||
}
|
||||
|
||||
void CDMRNetwork::close()
|
||||
{
|
||||
LogMessage("DMR, Closing DMR Network");
|
||||
|
||||
if (m_status == RUNNING) {
|
||||
unsigned char buffer[9U];
|
||||
::memcpy(buffer + 0U, "RPTCL", 5U);
|
||||
::memcpy(buffer + 5U, m_id, 4U);
|
||||
write(buffer, 9U);
|
||||
}
|
||||
|
||||
m_socket.close();
|
||||
|
||||
m_retryTimer.stop();
|
||||
m_timeoutTimer.stop();
|
||||
}
|
||||
|
||||
bool CDMRNetwork::clock(unsigned int ms)
|
||||
{
|
||||
bool r = false;
|
||||
m_delayBuffers[1U]->clock(ms);
|
||||
m_delayBuffers[2U]->clock(ms);
|
||||
|
||||
if (m_status == WAITING_CONNECT) {
|
||||
m_retryTimer.clock(ms);
|
||||
if (m_retryTimer.isRunning() && m_retryTimer.hasExpired()) {
|
||||
bool ret = m_socket.open();
|
||||
if (ret) {
|
||||
ret = writeLogin();
|
||||
if (!ret)
|
||||
return true;
|
||||
|
||||
m_status = WAITING_LOGIN;
|
||||
m_timeoutTimer.start();
|
||||
}
|
||||
|
||||
m_retryTimer.start();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
in_addr address;
|
||||
unsigned int port;
|
||||
int length = m_socket.read(m_buffer, BUFFER_LENGTH, address, port);
|
||||
if (length < 0) {
|
||||
LogError("DMR, Socket has failed, retrying connection to the master");
|
||||
close();
|
||||
open();
|
||||
return true;
|
||||
}
|
||||
|
||||
// if (m_debug && length > 0)
|
||||
// CUtils::dump(1U, "Network Received", m_buffer, length);
|
||||
|
||||
if (length > 0 && m_address.s_addr == address.s_addr && m_port == port) {
|
||||
if (::memcmp(m_buffer, "DMRD", 4U) == 0) {
|
||||
if (m_enabled) {
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "Network Received", m_buffer, length);
|
||||
receiveData(m_buffer, length);
|
||||
}
|
||||
} else if (::memcmp(m_buffer, "MSTNAK", 6U) == 0) {
|
||||
if (m_status == RUNNING) {
|
||||
LogWarning("DMR, Login to the master has failed, retrying login ...");
|
||||
m_status = WAITING_LOGIN;
|
||||
m_timeoutTimer.start();
|
||||
m_retryTimer.start();
|
||||
} else {
|
||||
/* Once the modem death spiral has been prevented in Modem.cpp
|
||||
the Network sometimes times out and reaches here.
|
||||
We want it to reconnect so... */
|
||||
LogError("DMR, Login to the master has failed, retrying network ...");
|
||||
close();
|
||||
open();
|
||||
return true;
|
||||
}
|
||||
} else if (::memcmp(m_buffer, "RPTACK", 6U) == 0) {
|
||||
switch (m_status) {
|
||||
case WAITING_LOGIN:
|
||||
LogDebug("DMR, Sending authorisation");
|
||||
::memcpy(m_salt, m_buffer + 6U, sizeof(uint32_t));
|
||||
writeAuthorisation();
|
||||
m_status = WAITING_AUTHORISATION;
|
||||
m_timeoutTimer.start();
|
||||
m_retryTimer.start();
|
||||
break;
|
||||
case WAITING_AUTHORISATION:
|
||||
LogDebug("DMR, Sending configuration");
|
||||
writeConfig();
|
||||
m_status = WAITING_CONFIG;
|
||||
m_timeoutTimer.start();
|
||||
m_retryTimer.start();
|
||||
break;
|
||||
case WAITING_CONFIG:
|
||||
if (m_options.empty()) {
|
||||
LogMessage("DMR, Logged into the master successfully");
|
||||
m_status = RUNNING;
|
||||
} else {
|
||||
LogDebug("DMR, Sending options");
|
||||
writeOptions();
|
||||
m_status = WAITING_OPTIONS;
|
||||
}
|
||||
m_timeoutTimer.start();
|
||||
m_retryTimer.start();
|
||||
break;
|
||||
case WAITING_OPTIONS:
|
||||
LogMessage("DMR, Logged into the master successfully");
|
||||
m_status = RUNNING;
|
||||
m_timeoutTimer.start();
|
||||
m_retryTimer.start();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (::memcmp(m_buffer, "MSTCL", 5U) == 0) {
|
||||
LogError("DMR, Master is closing down");
|
||||
close();
|
||||
open();
|
||||
r = true;
|
||||
} else if (::memcmp(m_buffer, "MSTPONG", 7U) == 0) {
|
||||
m_timeoutTimer.start();
|
||||
} else if (::memcmp(m_buffer, "RPTSBKN", 7U) == 0) {
|
||||
m_beacon = true;
|
||||
} else {
|
||||
CUtils::dump("Unknown packet from the master", m_buffer, length);
|
||||
}
|
||||
}
|
||||
|
||||
m_retryTimer.clock(ms);
|
||||
if (m_retryTimer.isRunning() && m_retryTimer.hasExpired()) {
|
||||
switch (m_status) {
|
||||
case WAITING_LOGIN:
|
||||
writeLogin();
|
||||
break;
|
||||
case WAITING_AUTHORISATION:
|
||||
writeAuthorisation();
|
||||
break;
|
||||
case WAITING_OPTIONS:
|
||||
writeOptions();
|
||||
break;
|
||||
case WAITING_CONFIG:
|
||||
writeConfig();
|
||||
break;
|
||||
case RUNNING:
|
||||
writePing();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
m_retryTimer.start();
|
||||
}
|
||||
|
||||
m_timeoutTimer.clock(ms);
|
||||
if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) {
|
||||
LogError("DMR, Connection to the master has timed out, retrying connection");
|
||||
close();
|
||||
open();
|
||||
r = true;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void CDMRNetwork::reset(unsigned int slotNo)
|
||||
{
|
||||
assert(slotNo == 1U || slotNo == 2U);
|
||||
|
||||
if (slotNo == 1U) {
|
||||
m_delayBuffers[1U]->reset();
|
||||
m_streamId[0U] = ::rand() + 1U;
|
||||
} else {
|
||||
m_delayBuffers[2U]->reset();
|
||||
m_streamId[1U] = ::rand() + 1U;
|
||||
}
|
||||
}
|
||||
|
||||
bool CDMRNetwork::isConnected() const
|
||||
{
|
||||
return m_status == RUNNING;
|
||||
}
|
||||
|
||||
void CDMRNetwork::receiveData(const unsigned char* data, unsigned int length)
|
||||
{
|
||||
assert(data != NULL);
|
||||
assert(length > 0U);
|
||||
|
||||
unsigned int slotNo = (data[15U] & 0x80U) == 0x80U ? 2U : 1U;
|
||||
|
||||
// DMO mode slot disabling
|
||||
if (slotNo == 1U && !m_duplex)
|
||||
return;
|
||||
|
||||
// Individual slot disabling
|
||||
if (slotNo == 1U && !m_slot1)
|
||||
return;
|
||||
if (slotNo == 2U && !m_slot2)
|
||||
return;
|
||||
|
||||
m_delayBuffers[slotNo]->addData(data, length);
|
||||
|
||||
}
|
||||
|
||||
bool CDMRNetwork::writeLogin()
|
||||
{
|
||||
unsigned char buffer[8U];
|
||||
|
||||
::memcpy(buffer + 0U, "RPTL", 4U);
|
||||
::memcpy(buffer + 4U, m_id, 4U);
|
||||
|
||||
return write(buffer, 8U);
|
||||
}
|
||||
|
||||
bool CDMRNetwork::writeAuthorisation()
|
||||
{
|
||||
size_t size = m_password.size();
|
||||
|
||||
unsigned char* in = new unsigned char[size + sizeof(uint32_t)];
|
||||
::memcpy(in, m_salt, sizeof(uint32_t));
|
||||
for (size_t i = 0U; i < size; i++)
|
||||
in[i + sizeof(uint32_t)] = m_password.at(i);
|
||||
|
||||
unsigned char out[40U];
|
||||
::memcpy(out + 0U, "RPTK", 4U);
|
||||
::memcpy(out + 4U, m_id, 4U);
|
||||
|
||||
CSHA256 sha256;
|
||||
sha256.buffer(in, (unsigned int)(size + sizeof(uint32_t)), out + 8U);
|
||||
|
||||
delete[] in;
|
||||
|
||||
return write(out, 40U);
|
||||
}
|
||||
|
||||
bool CDMRNetwork::writeOptions()
|
||||
{
|
||||
char buffer[300U];
|
||||
|
||||
::memcpy(buffer + 0U, "RPTO", 4U);
|
||||
::memcpy(buffer + 4U, m_id, 4U);
|
||||
::strcpy(buffer + 8U, m_options.c_str());
|
||||
|
||||
return write((unsigned char*)buffer, (unsigned int)m_options.length() + 8U);
|
||||
}
|
||||
|
||||
bool CDMRNetwork::writeConfig()
|
||||
{
|
||||
const char* software;
|
||||
char slots = '0';
|
||||
if (m_duplex) {
|
||||
if (m_slot1 && m_slot2)
|
||||
slots = '3';
|
||||
else if (m_slot1 && !m_slot2)
|
||||
slots = '1';
|
||||
else if (!m_slot1 && m_slot2)
|
||||
slots = '2';
|
||||
|
||||
switch (m_hwType) {
|
||||
case HWT_MMDVM:
|
||||
software = "MMDVM";
|
||||
break;
|
||||
case HWT_MMDVM_HS:
|
||||
software = "MMDVM_MMDVM_HS";
|
||||
break;
|
||||
default:
|
||||
software = "MMDVM_Unknown";
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
slots = '4';
|
||||
|
||||
switch (m_hwType) {
|
||||
case HWT_MMDVM:
|
||||
software = "MMDVM_DMO";
|
||||
break;
|
||||
case HWT_DVMEGA:
|
||||
software = "MMDVM_DVMega";
|
||||
break;
|
||||
case HWT_MMDVM_ZUMSPOT:
|
||||
software = "MMDVM_ZUMspot";
|
||||
break;
|
||||
case HWT_MMDVM_HS_HAT:
|
||||
software = "MMDVM_MMDVM_HS_Hat";
|
||||
break;
|
||||
case HWT_MMDVM_HS:
|
||||
software = "MMDVM_MMDVM_HS";
|
||||
break;
|
||||
default:
|
||||
software = "MMDVM_Unknown";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
char buffer[400U];
|
||||
|
||||
::memcpy(buffer + 0U, "RPTC", 4U);
|
||||
::memcpy(buffer + 4U, m_id, 4U);
|
||||
|
||||
char latitude[20U];
|
||||
::sprintf(latitude, "%08f", m_latitude);
|
||||
|
||||
char longitude[20U];
|
||||
::sprintf(longitude, "%09f", m_longitude);
|
||||
|
||||
unsigned int power = m_power;
|
||||
if (power > 99U)
|
||||
power = 99U;
|
||||
|
||||
int height = m_height;
|
||||
if (height > 999)
|
||||
height = 999;
|
||||
|
||||
::sprintf(buffer + 8U, "%-8.8s%09u%09u%02u%02u%8.8s%9.9s%03d%-20.20s%-19.19s%c%-124.124s%-40.40s%-40.40s", m_callsign.c_str(),
|
||||
m_rxFrequency, m_txFrequency, power, m_colorCode, latitude, longitude, height, m_location.c_str(),
|
||||
m_description.c_str(), slots, m_url.c_str(), m_version, software);
|
||||
|
||||
return write((unsigned char*)buffer, 302U);
|
||||
}
|
||||
|
||||
bool CDMRNetwork::writePing()
|
||||
{
|
||||
unsigned char buffer[11U];
|
||||
|
||||
::memcpy(buffer + 0U, "RPTPING", 7U);
|
||||
::memcpy(buffer + 7U, m_id, 4U);
|
||||
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "DMR Network Ping Sent", buffer, 11U);
|
||||
|
||||
return write(buffer, 11U);
|
||||
}
|
||||
|
||||
bool CDMRNetwork::wantsBeacon()
|
||||
{
|
||||
bool beacon = m_beacon;
|
||||
|
||||
m_beacon = false;
|
||||
|
||||
return beacon;
|
||||
}
|
||||
|
||||
bool CDMRNetwork::write(const unsigned char* data, unsigned int length)
|
||||
{
|
||||
assert(data != NULL);
|
||||
assert(length > 0U);
|
||||
|
||||
// if (m_debug)
|
||||
// CUtils::dump(1U, "Network Transmitted", data, length);
|
||||
|
||||
bool ret = m_socket.write(data, length, m_address, m_port);
|
||||
if (!ret) {
|
||||
LogError("DMR, Socket has failed when writing data to the master, retrying connection");
|
||||
m_socket.close();
|
||||
open();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* Copyright (C) 2015,2016,2017,2018 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(DMRNetwork_H)
|
||||
#define DMRNetwork_H
|
||||
|
||||
#include "DelayBuffer.h"
|
||||
#include "UDPSocket.h"
|
||||
#include "Timer.h"
|
||||
#include "DMRData.h"
|
||||
#include "Defines.h"
|
||||
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
class CDMRNetwork
|
||||
{
|
||||
public:
|
||||
CDMRNetwork(const std::string& address, unsigned int port, unsigned int local, unsigned int id, const std::string& password, bool duplex, const char* version, bool debug, bool slot1, bool slot2, HW_TYPE hwType, unsigned int jitter);
|
||||
~CDMRNetwork();
|
||||
|
||||
void setOptions(const std::string& options);
|
||||
|
||||
void setConfig(const std::string& callsign, unsigned int rxFrequency, unsigned int txFrequency, unsigned int power, unsigned int colorCode, float latitude, float longitude, int height, const std::string& location, const std::string& description, const std::string& url);
|
||||
|
||||
bool open();
|
||||
|
||||
void enable(bool enabled);
|
||||
|
||||
bool read(CDMRData& data);
|
||||
|
||||
bool write(const CDMRData& data);
|
||||
|
||||
bool writePosition(unsigned int id, const unsigned char* data);
|
||||
|
||||
bool writeTalkerAlias(unsigned int id, unsigned char type, const unsigned char* data);
|
||||
|
||||
bool wantsBeacon();
|
||||
|
||||
bool clock(unsigned int ms);
|
||||
|
||||
void reset(unsigned int slotNo);
|
||||
|
||||
bool isConnected() const;
|
||||
|
||||
void close();
|
||||
|
||||
private:
|
||||
in_addr m_address;
|
||||
unsigned int m_port;
|
||||
uint8_t* m_id;
|
||||
std::string m_password;
|
||||
bool m_duplex;
|
||||
const char* m_version;
|
||||
bool m_debug;
|
||||
CUDPSocket m_socket;
|
||||
bool m_enabled;
|
||||
bool m_slot1;
|
||||
bool m_slot2;
|
||||
CDelayBuffer** m_delayBuffers;
|
||||
HW_TYPE m_hwType;
|
||||
|
||||
enum STATUS {
|
||||
WAITING_CONNECT,
|
||||
WAITING_LOGIN,
|
||||
WAITING_AUTHORISATION,
|
||||
WAITING_CONFIG,
|
||||
WAITING_OPTIONS,
|
||||
RUNNING
|
||||
};
|
||||
|
||||
STATUS m_status;
|
||||
CTimer m_retryTimer;
|
||||
CTimer m_timeoutTimer;
|
||||
unsigned char* m_buffer;
|
||||
unsigned char* m_salt;
|
||||
uint32_t* m_streamId;
|
||||
|
||||
std::string m_options;
|
||||
|
||||
std::string m_callsign;
|
||||
unsigned int m_rxFrequency;
|
||||
unsigned int m_txFrequency;
|
||||
unsigned int m_power;
|
||||
unsigned int m_colorCode;
|
||||
float m_latitude;
|
||||
float m_longitude;
|
||||
int m_height;
|
||||
std::string m_location;
|
||||
std::string m_description;
|
||||
std::string m_url;
|
||||
|
||||
bool m_beacon;
|
||||
|
||||
bool writeLogin();
|
||||
bool writeAuthorisation();
|
||||
bool writeOptions();
|
||||
bool writeConfig();
|
||||
bool writePing();
|
||||
|
||||
bool write(const unsigned char* data, unsigned int length);
|
||||
|
||||
void receiveData(const unsigned char* data, unsigned int length);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -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 <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
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;
|
||||
}
|
|
@ -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
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#if !defined(Defines_H)
|
||||
#define Defines_H
|
||||
|
||||
const unsigned char MODE_IDLE = 0U;
|
||||
const unsigned char MODE_DSTAR = 1U;
|
||||
const unsigned char MODE_DMR = 2U;
|
||||
const unsigned char MODE_YSF = 3U;
|
||||
const unsigned char MODE_P25 = 4U;
|
||||
const unsigned char MODE_NXDN = 5U;
|
||||
const unsigned char MODE_CW = 98U;
|
||||
const unsigned char MODE_LOCKOUT = 99U;
|
||||
const unsigned char MODE_ERROR = 100U;
|
||||
|
||||
const unsigned char TAG_HEADER = 0x00U;
|
||||
const unsigned char TAG_DATA = 0x01U;
|
||||
const unsigned char TAG_LOST = 0x02U;
|
||||
const unsigned char TAG_EOT = 0x03U;
|
||||
const unsigned char TAG_NODATA = 0x04U;
|
||||
|
||||
enum HW_TYPE {
|
||||
HWT_MMDVM,
|
||||
HWT_DVMEGA,
|
||||
HWT_MMDVM_ZUMSPOT,
|
||||
HWT_MMDVM_HS_HAT,
|
||||
HWT_NANO_HOTSPOT,
|
||||
HWT_MMDVM_HS,
|
||||
HWT_UNKNOWN
|
||||
};
|
||||
|
||||
enum RPT_RF_STATE {
|
||||
RS_RF_LISTENING,
|
||||
RS_RF_LATE_ENTRY,
|
||||
RS_RF_AUDIO,
|
||||
RS_RF_DATA,
|
||||
RS_RF_REJECTED,
|
||||
RS_RF_INVALID
|
||||
};
|
||||
|
||||
enum RPT_NET_STATE {
|
||||
RS_NET_IDLE,
|
||||
RS_NET_AUDIO,
|
||||
RS_NET_DATA
|
||||
};
|
||||
|
||||
enum B_STATUS {
|
||||
BS_NO_DATA,
|
||||
BS_DATA,
|
||||
BS_MISSING
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* Copyright (C) 2018 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 "DelayBuffer.h"
|
||||
#include "DMRDefines.h"
|
||||
|
||||
#include "Log.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
CDelayBuffer::CDelayBuffer(const std::string& name, unsigned int blockSize, unsigned int blockTime, unsigned int jitterTime, bool debug) :
|
||||
m_name(name),
|
||||
m_blockSize(blockSize),
|
||||
m_blockTime(blockTime),
|
||||
m_debug(debug),
|
||||
m_timer(1000U, 0U, jitterTime),
|
||||
m_stopWatch(),
|
||||
m_running(false),
|
||||
m_buffer(5000U, name.c_str()),
|
||||
m_outputCount(0U),
|
||||
m_lastData(NULL),
|
||||
m_lastDataLength(0U),
|
||||
m_lastDataValid(false)
|
||||
{
|
||||
assert(blockSize > 0U);
|
||||
assert(blockTime > 0U);
|
||||
assert(jitterTime > 0U);
|
||||
|
||||
m_lastData = new unsigned char[m_blockSize];
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
CDelayBuffer::~CDelayBuffer()
|
||||
{
|
||||
delete[] m_lastData;
|
||||
}
|
||||
|
||||
bool CDelayBuffer::addData(const unsigned char* data, unsigned int length)
|
||||
{
|
||||
assert(data != NULL);
|
||||
assert(length > 0U);
|
||||
assert(length == m_blockSize);
|
||||
|
||||
if (m_debug)
|
||||
LogDebug("%s, DelayBuffer: appending data", m_name.c_str());
|
||||
|
||||
m_buffer.addData(data, length);
|
||||
|
||||
if (!m_timer.isRunning()) {
|
||||
if (m_debug)
|
||||
LogDebug("%s, DelayBuffer: starting the timer from append", m_name.c_str());
|
||||
m_timer.start();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
B_STATUS CDelayBuffer::getData(unsigned char* data, unsigned int& length)
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
if (!m_running)
|
||||
return BS_NO_DATA;
|
||||
|
||||
unsigned int needed = m_stopWatch.elapsed() / m_blockTime + 2U;
|
||||
if (needed <= m_outputCount)
|
||||
return BS_NO_DATA;
|
||||
|
||||
if (!m_buffer.isEmpty()) {
|
||||
if (m_debug)
|
||||
LogDebug("%s, DelayBuffer: returning data, elapsed=%ums", m_name.c_str(), m_stopWatch.elapsed());
|
||||
|
||||
if (m_buffer.getData(data, m_blockSize)) {
|
||||
length = m_blockSize;
|
||||
|
||||
// Save this data in case no more data is available next time
|
||||
::memcpy(m_lastData, data, length);
|
||||
m_lastDataLength = length;
|
||||
m_lastDataValid = true;
|
||||
|
||||
m_outputCount++;
|
||||
|
||||
return BS_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_debug)
|
||||
LogDebug("%s, DelayBuffer: no data available, elapsed=%ums", m_name.c_str(), m_stopWatch.elapsed());
|
||||
|
||||
// Return the last data frame if we have it
|
||||
if (m_lastDataLength > 0U) {
|
||||
if(m_lastDataValid) {
|
||||
if (m_debug)
|
||||
LogDebug("%s, DelayBuffer: returning the last received frame", m_name.c_str());
|
||||
// Copy last valid data
|
||||
::memcpy(data, m_lastData, m_lastDataLength);
|
||||
} else {
|
||||
if (m_debug)
|
||||
LogDebug("%s, DelayBuffer: returning a silence frame", m_name.c_str());
|
||||
// Copy last network header data
|
||||
::memcpy(data, m_lastData, 20U);
|
||||
// We only need to copy silence AMBE data, don't care about LC data for next YSF conversion stage
|
||||
::memcpy(data + 20U, DMR_SILENCE_DATA, 33U);
|
||||
data[53U] = 0U;
|
||||
data[54U] = 0U;
|
||||
}
|
||||
|
||||
m_lastDataValid = false;
|
||||
length = m_lastDataLength;
|
||||
|
||||
m_outputCount++;
|
||||
|
||||
return BS_MISSING;
|
||||
}
|
||||
|
||||
return BS_NO_DATA;
|
||||
}
|
||||
|
||||
void CDelayBuffer::reset()
|
||||
{
|
||||
m_buffer.clear();
|
||||
|
||||
m_lastDataLength = 0U;
|
||||
|
||||
m_outputCount = 0U;
|
||||
|
||||
m_timer.stop();
|
||||
|
||||
m_running = false;
|
||||
}
|
||||
|
||||
void CDelayBuffer::clock(unsigned int ms)
|
||||
{
|
||||
m_timer.clock(ms);
|
||||
if (m_timer.isRunning() && m_timer.hasExpired()) {
|
||||
if (!m_running) {
|
||||
m_stopWatch.start();
|
||||
m_running = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (C) 2018 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(DELAYBUFFER_H)
|
||||
#define DELAYBUFFER_H
|
||||
|
||||
#include "RingBuffer.h"
|
||||
#include "StopWatch.h"
|
||||
#include "Defines.h"
|
||||
#include "Timer.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class CDelayBuffer {
|
||||
public:
|
||||
CDelayBuffer(const std::string& name, unsigned int blockSize, unsigned int blockTime, unsigned int jitterTime, bool debug);
|
||||
~CDelayBuffer();
|
||||
|
||||
bool addData(const unsigned char* data, unsigned int length);
|
||||
|
||||
B_STATUS getData(unsigned char* data, unsigned int& length);
|
||||
|
||||
void reset();
|
||||
|
||||
void clock(unsigned int ms);
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
unsigned int m_blockSize;
|
||||
unsigned int m_blockTime;
|
||||
bool m_debug;
|
||||
CTimer m_timer;
|
||||
CStopWatch m_stopWatch;
|
||||
bool m_running;
|
||||
CRingBuffer<unsigned char> m_buffer;
|
||||
unsigned int m_outputCount;
|
||||
|
||||
unsigned char* m_lastData;
|
||||
unsigned int m_lastDataLength;
|
||||
bool m_lastDataValid;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -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 <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
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;
|
||||
}
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (C) 2010,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 Golay24128_H
|
||||
#define Golay24128_H
|
||||
|
||||
class CGolay24128 {
|
||||
public:
|
||||
static unsigned int encode23127(unsigned int data);
|
||||
static unsigned int encode24128(unsigned int data);
|
||||
|
||||
static unsigned int decode23127(unsigned int code);
|
||||
static unsigned int decode24128(unsigned int code);
|
||||
static unsigned int decode24128(unsigned char* bytes);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -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 <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
// 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];
|
||||
}
|
|
@ -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
|
|
@ -0,0 +1,340 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* 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 "Log.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstdarg>
|
||||
#include <ctime>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
static unsigned int m_fileLevel = 2U;
|
||||
static std::string m_filePath;
|
||||
static std::string m_fileRoot;
|
||||
|
||||
static FILE* m_fpLog = NULL;
|
||||
|
||||
static unsigned int m_displayLevel = 2U;
|
||||
|
||||
static struct tm m_tm;
|
||||
|
||||
static char LEVELS[] = " DMIWEF";
|
||||
|
||||
static bool LogOpen()
|
||||
{
|
||||
if (m_fileLevel == 0U)
|
||||
return true;
|
||||
|
||||
time_t now;
|
||||
::time(&now);
|
||||
|
||||
struct tm* tm = ::gmtime(&now);
|
||||
|
||||
if (tm->tm_mday == m_tm.tm_mday && tm->tm_mon == m_tm.tm_mon && tm->tm_year == m_tm.tm_year) {
|
||||
if (m_fpLog != NULL)
|
||||
return true;
|
||||
} else {
|
||||
if (m_fpLog != NULL)
|
||||
::fclose(m_fpLog);
|
||||
}
|
||||
|
||||
char filename[100U];
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
::sprintf(filename, "%s\\%s-%04d-%02d-%02d.log", m_filePath.c_str(), m_fileRoot.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
|
||||
#else
|
||||
::sprintf(filename, "%s/%s-%04d-%02d-%02d.log", m_filePath.c_str(), m_fileRoot.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
|
||||
#endif
|
||||
|
||||
m_fpLog = ::fopen(filename, "a+t");
|
||||
m_tm = *tm;
|
||||
|
||||
return m_fpLog != NULL;
|
||||
}
|
||||
|
||||
bool LogInitialise(const std::string& filePath, const std::string& fileRoot, unsigned int fileLevel, unsigned int displayLevel)
|
||||
{
|
||||
m_filePath = filePath;
|
||||
m_fileRoot = fileRoot;
|
||||
m_fileLevel = fileLevel;
|
||||
m_displayLevel = displayLevel;
|
||||
return ::LogOpen();
|
||||
}
|
||||
|
||||
void LogFinalise()
|
||||
{
|
||||
if (m_fpLog != NULL)
|
||||
::fclose(m_fpLog);
|
||||
}
|
||||
|
||||
void Log(unsigned int level, const char* fmt, ...)
|
||||
{
|
||||
assert(fmt != NULL);
|
||||
|
||||
char buffer[300U];
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
SYSTEMTIME st;
|
||||
::GetSystemTime(&st);
|
||||
|
||||
::sprintf(buffer, "%c: %04u-%02u-%02u %02u:%02u:%02u.%03u ", LEVELS[level], st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
|
||||
#else
|
||||
struct timeval now;
|
||||
::gettimeofday(&now, NULL);
|
||||
|
||||
struct tm* tm = ::gmtime(&now.tv_sec);
|
||||
|
||||
::sprintf(buffer, "%c: %04d-%02d-%02d %02d:%02d:%02d.%03lu ", LEVELS[level], tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec / 1000U);
|
||||
#endif
|
||||
|
||||
va_list vl;
|
||||
va_start(vl, fmt);
|
||||
|
||||
::vsprintf(buffer + ::strlen(buffer), fmt, vl);
|
||||
|
||||
va_end(vl);
|
||||
|
||||
if (level >= m_fileLevel && m_fileLevel != 0U) {
|
||||
bool ret = ::LogOpen();
|
||||
if (!ret)
|
||||
return;
|
||||
|
||||
::fprintf(m_fpLog, "%s\n", buffer);
|
||||
::fflush(m_fpLog);
|
||||
}
|
||||
|
||||
if (level >= m_displayLevel && m_displayLevel != 0U) {
|
||||
::fprintf(stdout, "%s\n", buffer);
|
||||
::fflush(stdout);
|
||||
}
|
||||
|
||||
if (level == 6U) { // Fatal
|
||||
::fclose(m_fpLog);
|
||||
exit(1);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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(LOG_H)
|
||||
#define LOG_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#define LogDebug(fmt, ...) Log(1U, fmt, ##__VA_ARGS__)
|
||||
#define LogMessage(fmt, ...) Log(2U, fmt, ##__VA_ARGS__)
|
||||
#define LogInfo(fmt, ...) Log(3U, fmt, ##__VA_ARGS__)
|
||||
#define LogWarning(fmt, ...) Log(4U, fmt, ##__VA_ARGS__)
|
||||
#define LogError(fmt, ...) Log(5U, fmt, ##__VA_ARGS__)
|
||||
#define LogFatal(fmt, ...) Log(6U, fmt, ##__VA_ARGS__)
|
||||
|
||||
extern void Log(unsigned int level, const char* fmt, ...);
|
||||
|
||||
extern bool LogInitialise(const std::string& filePath, const std::string& fileRoot, unsigned int fileLevel, unsigned int displayLevel);
|
||||
extern void LogFinalise();
|
||||
|
||||
#endif
|
|
@ -0,0 +1,863 @@
|
|||
/*
|
||||
* Copyright (C) 2016,2017 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||
* Copyright (C) 2020 by Doug McLain AD8DP
|
||||
*
|
||||
* 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 "M172DMR.h"
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#define DMR_FRAME_PER 55U
|
||||
#define M17_FRAME_PER 35U
|
||||
|
||||
#define XLX_SLOT 2U
|
||||
#define XLX_COLOR_CODE 3U
|
||||
|
||||
const char* DEFAULT_INI_FILE = "/etc/M172DMR.ini";
|
||||
|
||||
const char* HEADER1 = "This software is for use on amateur radio networks only,";
|
||||
const char* HEADER2 = "it is to be used for educational purposes only. Its use on";
|
||||
const char* HEADER3 = "commercial networks is strictly prohibited.";
|
||||
const char* HEADER4 = "Copyright(C) 2018 by AD8DP, CA6JAU, G4KLX and others";
|
||||
|
||||
#define M17CHARACTERS " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/."
|
||||
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <clocale>
|
||||
#include <cctype>
|
||||
|
||||
int end = 0;
|
||||
|
||||
void sig_handler(int signo)
|
||||
{
|
||||
if (signo == SIGTERM) {
|
||||
end = 1;
|
||||
::fprintf(stdout, "Received SIGTERM\n");
|
||||
}
|
||||
}
|
||||
|
||||
void encode_callsign(uint8_t *callsign)
|
||||
{
|
||||
const std::string m17_alphabet(M17CHARACTERS);
|
||||
char cs[10];
|
||||
memset(cs, 0, sizeof(cs));
|
||||
memcpy(cs, callsign, strlen((char *)callsign));
|
||||
uint64_t encoded = 0;
|
||||
for(int i = std::strlen((char *)callsign)-1; i >= 0; i--) {
|
||||
auto pos = m17_alphabet.find(cs[i]);
|
||||
if (pos == std::string::npos) {
|
||||
pos = 0;
|
||||
}
|
||||
encoded *= 40;
|
||||
encoded += pos;
|
||||
}
|
||||
for (int i=0; i<6; i++) {
|
||||
callsign[i] = (encoded >> (8*(5-i)) & 0xFFU);
|
||||
}
|
||||
}
|
||||
|
||||
void decode_callsign(uint8_t *callsign)
|
||||
{
|
||||
const std::string m17_alphabet(M17CHARACTERS);
|
||||
uint8_t code[6];
|
||||
uint64_t coded = callsign[0];
|
||||
for (int i=1; i<6; i++)
|
||||
coded = (coded << 8) | callsign[i];
|
||||
if (coded > 0xee6b27ffffffu) {
|
||||
//std::cerr << "Callsign code is too large, 0x" << std::hex << coded << std::endl;
|
||||
return;
|
||||
}
|
||||
memcpy(code, callsign, 6);
|
||||
memset(callsign, 0, 10);
|
||||
int i = 0;
|
||||
while (coded) {
|
||||
callsign[i++] = m17_alphabet[coded % 40];
|
||||
coded /= 40;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
const char* iniFile = DEFAULT_INI_FILE;
|
||||
if (argc > 1) {
|
||||
for (int currentArg = 1; currentArg < argc; ++currentArg) {
|
||||
std::string arg = argv[currentArg];
|
||||
if ((arg == "-v") || (arg == "--version")) {
|
||||
::fprintf(stdout, "P252DMR version %s\n", VERSION);
|
||||
return 0;
|
||||
} else if (arg.substr(0, 1) == "-") {
|
||||
::fprintf(stderr, "Usage: P252DMR [-v|--version] [filename]\n");
|
||||
return 1;
|
||||
} else {
|
||||
iniFile = argv[currentArg];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Capture SIGTERM to finish gracelessly
|
||||
if (signal(SIGTERM, sig_handler) == SIG_ERR)
|
||||
::fprintf(stdout, "Can't catch SIGTERM\n");
|
||||
|
||||
CM172DMR* gateway = new CM172DMR(std::string(iniFile));
|
||||
|
||||
int ret = gateway->run();
|
||||
|
||||
delete gateway;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
CM172DMR::CM172DMR(const std::string& configFile) :
|
||||
m_callsign(),
|
||||
m_m17Ref(),
|
||||
m_conf(configFile),
|
||||
m_dmrNetwork(NULL),
|
||||
m_dmrlookup(NULL),
|
||||
m_conv(),
|
||||
m_colorcode(1U),
|
||||
m_srcHS(1U),
|
||||
m_defsrcid(1U),
|
||||
m_dstid(1U),
|
||||
m_dmrpc(false),
|
||||
m_dmrSrc(1U),
|
||||
m_dmrDst(1U),
|
||||
m_dmrLastDT(0U),
|
||||
m_m17Frame(NULL),
|
||||
m_m17Frames(0U),
|
||||
m_dmrFrame(NULL),
|
||||
m_dmrFrames(0U),
|
||||
m_EmbeddedLC(),
|
||||
m_dmrflco(FLCO_GROUP),
|
||||
m_dmrinfo(false),
|
||||
m_xlxmodule(),
|
||||
m_xlxConnected(false),
|
||||
m_xlxReflectors(NULL),
|
||||
m_xlxrefl(0U),
|
||||
m_firstSync(false)
|
||||
{
|
||||
m_m17Frame = new unsigned char[100U];
|
||||
m_dmrFrame = new unsigned char[50U];
|
||||
|
||||
::memset(m_m17Frame, 0U, 100U);
|
||||
::memset(m_dmrFrame, 0U, 50U);
|
||||
}
|
||||
|
||||
CM172DMR::~CM172DMR()
|
||||
{
|
||||
delete[] m_m17Frame;
|
||||
delete[] m_dmrFrame;
|
||||
}
|
||||
|
||||
int CM172DMR::run()
|
||||
{
|
||||
bool ret = m_conf.read();
|
||||
if (!ret) {
|
||||
::fprintf(stderr, "M172DMR: cannot read the .ini file\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
setlocale(LC_ALL, "C");
|
||||
|
||||
unsigned int logDisplayLevel = m_conf.getLogDisplayLevel();
|
||||
|
||||
if(m_conf.getDaemon())
|
||||
logDisplayLevel = 0U;
|
||||
|
||||
bool m_daemon = m_conf.getDaemon();
|
||||
if (m_daemon) {
|
||||
// Create new process
|
||||
pid_t pid = ::fork();
|
||||
if (pid == -1) {
|
||||
::fprintf(stderr, "Couldn't fork() , exiting\n");
|
||||
return -1;
|
||||
} else if (pid != 0)
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
// Create new session and process group
|
||||
if (::setsid() == -1) {
|
||||
::fprintf(stderr, "Couldn't setsid(), exiting\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Set the working directory to the root directory
|
||||
if (::chdir("/") == -1) {
|
||||
::fprintf(stderr, "Couldn't cd /, exiting\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// If we are currently root...
|
||||
if (getuid() == 0) {
|
||||
struct passwd* user = ::getpwnam("mmdvm");
|
||||
if (user == NULL) {
|
||||
::fprintf(stderr, "Could not get the mmdvm user, exiting\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uid_t mmdvm_uid = user->pw_uid;
|
||||
gid_t mmdvm_gid = user->pw_gid;
|
||||
|
||||
// Set user and group ID's to mmdvm:mmdvm
|
||||
if (setgid(mmdvm_gid) != 0) {
|
||||
::fprintf(stderr, "Could not set mmdvm GID, exiting\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setuid(mmdvm_uid) != 0) {
|
||||
::fprintf(stderr, "Could not set mmdvm UID, exiting\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Double check it worked (AKA Paranoia)
|
||||
if (setuid(0) != -1) {
|
||||
::fprintf(stderr, "It's possible to regain root - something is wrong!, exiting\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = ::LogInitialise(m_conf.getLogFilePath(), m_conf.getLogFileRoot(), m_conf.getLogFileLevel(), logDisplayLevel);
|
||||
if (!ret) {
|
||||
::fprintf(stderr, "M172DMR: unable to open the log file\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (m_daemon) {
|
||||
::close(STDIN_FILENO);
|
||||
::close(STDOUT_FILENO);
|
||||
::close(STDERR_FILENO);
|
||||
}
|
||||
|
||||
LogInfo(HEADER1);
|
||||
LogInfo(HEADER2);
|
||||
LogInfo(HEADER3);
|
||||
LogInfo(HEADER4);
|
||||
|
||||
m_callsign = m_conf.getCallsign();
|
||||
m_m17Ref = m_conf.getM17DstName();
|
||||
char module = m_m17Ref.c_str()[m_m17Ref.find(' ')+1];
|
||||
|
||||
std::string m17_dstAddress = m_conf.getM17DstAddress();
|
||||
unsigned int m17_dstPort = m_conf.getM17DstPort();
|
||||
std::string m17_localAddress = m_conf.getM17LocalAddress();
|
||||
unsigned int m17_localPort = m_conf.getM17LocalPort();
|
||||
bool m17_debug = m_conf.getM17NetworkDebug();
|
||||
|
||||
m_conv.setM17GainAdjDb(m_conf.getM17GainAdjDb());
|
||||
|
||||
uint16_t streamid = 0;
|
||||
unsigned char m17_src[10];
|
||||
unsigned char m17_dst[10];
|
||||
|
||||
memcpy(m17_src, m_callsign.c_str(), 9);
|
||||
m17_src[9] = 0x00;
|
||||
encode_callsign(m17_src);
|
||||
|
||||
std::string fileName = m_conf.getDMRXLXFile();
|
||||
m_xlxReflectors = new CReflectors(fileName, 60U);
|
||||
m_xlxReflectors->load();
|
||||
|
||||
m_m17Network = new CM17Network(m17_localAddress, m17_localPort, m17_dstAddress, m17_dstPort, m17_src, m17_debug);
|
||||
|
||||
ret = m_m17Network->open();
|
||||
if (!ret) {
|
||||
::LogError("Cannot open the M17 network port");
|
||||
::LogFinalise();
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = createDMRNetwork();
|
||||
if (!ret) {
|
||||
::LogError("Cannot open DMR Network");
|
||||
::LogFinalise();
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string lookupFile = m_conf.getDMRIdLookupFile();
|
||||
unsigned int reloadTime = m_conf.getDMRIdLookupTime();
|
||||
|
||||
m_dmrlookup = new CDMRLookup(lookupFile, reloadTime);
|
||||
m_dmrlookup->read();
|
||||
|
||||
if (m_dmrpc)
|
||||
m_dmrflco = FLCO_USER_USER;
|
||||
else
|
||||
m_dmrflco = FLCO_GROUP;
|
||||
|
||||
CTimer networkWatchdog(100U, 0U, 1500U);
|
||||
CTimer pollTimer(1000U, 5U);
|
||||
|
||||
std::string name = m_conf.getDescription();
|
||||
|
||||
CStopWatch stopWatch;
|
||||
CStopWatch m17Watch;
|
||||
CStopWatch dmrWatch;
|
||||
stopWatch.start();
|
||||
m17Watch.start();
|
||||
dmrWatch.start();
|
||||
pollTimer.start();
|
||||
|
||||
unsigned char m17_cnt = 0;
|
||||
unsigned char dmr_cnt = 0;
|
||||
|
||||
m_m17Network->writeLink(module);
|
||||
|
||||
LogMessage("Starting M172DMR-%s", VERSION);
|
||||
|
||||
for (; end == 0;) {
|
||||
unsigned char buffer[2000U];
|
||||
|
||||
CDMRData tx_dmrdata;
|
||||
unsigned int ms = stopWatch.elapsed();
|
||||
|
||||
if (m_dmrNetwork->isConnected() && !m_xlxmodule.empty() && !m_xlxConnected) {
|
||||
writeXLXLink(m_defsrcid, m_dstid, m_dmrNetwork);
|
||||
LogMessage("XLX, Linking to reflector XLX%03u, module %s", m_xlxrefl, m_xlxmodule.c_str());
|
||||
m_xlxConnected = true;
|
||||
}
|
||||
|
||||
while (m_m17Network->readData(m_m17Frame, 54U) > 0U) {
|
||||
//CUtils::dump(1U, "M17 Data", m_p25Frame, 22U);
|
||||
if (!memcmp(m_m17Frame, "M17 ", 4)) {
|
||||
if (m_m17Frame[34] == 0 && m_m17Frame[35] == 0) {
|
||||
m_m17Frames = 0;
|
||||
m_conv.putM17Header();
|
||||
}
|
||||
else if (m_m17Frame[34U] & 0x80U) {
|
||||
LogMessage("M17 received end of voice transmission, %.1f seconds", float(m_m17Frames) / 25.0F);
|
||||
m_conv.putM17EOT();
|
||||
}
|
||||
else{
|
||||
m_conv.putM17(m_m17Frame);
|
||||
}
|
||||
uint8_t cs[10];
|
||||
memcpy(cs, m_m17Frame+12, 6);
|
||||
decode_callsign(cs);
|
||||
std::string css((char *)cs);
|
||||
css = css.substr(0, css.find(' '));
|
||||
|
||||
int dmrid = m_dmrlookup->findID(css);
|
||||
if(dmrid){
|
||||
m_dmrSrc = dmrid;
|
||||
}
|
||||
m_m17Frames++;
|
||||
}
|
||||
}
|
||||
|
||||
if (dmrWatch.elapsed() > DMR_FRAME_PER) {
|
||||
unsigned int dmrFrameType = m_conv.getDMR(m_dmrFrame);
|
||||
|
||||
if(dmrFrameType == TAG_HEADER) {
|
||||
LogMessage("Sending DMR Header");
|
||||
CDMRData rx_dmrdata;
|
||||
dmr_cnt = 0U;
|
||||
|
||||
rx_dmrdata.setSlotNo(2U);
|
||||
rx_dmrdata.setSrcId(m_dmrSrc);
|
||||
rx_dmrdata.setDstId(m_dstid);
|
||||
rx_dmrdata.setFLCO(m_dmrflco);
|
||||
rx_dmrdata.setN(0U);
|
||||
rx_dmrdata.setSeqNo(0U);
|
||||
rx_dmrdata.setBER(0U);
|
||||
rx_dmrdata.setRSSI(0U);
|
||||
rx_dmrdata.setDataType(DT_VOICE_LC_HEADER);
|
||||
|
||||
// Add sync
|
||||
CSync::addDMRDataSync(m_dmrFrame, 0);
|
||||
|
||||
// Add SlotType
|
||||
CDMRSlotType slotType;
|
||||
slotType.setColorCode(m_colorcode);
|
||||
slotType.setDataType(DT_VOICE_LC_HEADER);
|
||||
slotType.getData(m_dmrFrame);
|
||||
|
||||
// Full LC
|
||||
CDMRLC dmrLC = CDMRLC(m_dmrflco, m_dmrSrc, m_dstid);
|
||||
CDMRFullLC fullLC;
|
||||
fullLC.encode(dmrLC, m_dmrFrame, DT_VOICE_LC_HEADER);
|
||||
m_EmbeddedLC.setLC(dmrLC);
|
||||
|
||||
rx_dmrdata.setData(m_dmrFrame);
|
||||
//CUtils::dump(1U, "DMR data:", m_dmrFrame, 33U);
|
||||
|
||||
for (unsigned int i = 0U; i < 3U; i++) {
|
||||
rx_dmrdata.setSeqNo(dmr_cnt);
|
||||
m_dmrNetwork->write(rx_dmrdata);
|
||||
dmr_cnt++;
|
||||
}
|
||||
|
||||
dmrWatch.start();
|
||||
}
|
||||
else if(dmrFrameType == TAG_EOT) {
|
||||
LogMessage("Sending DMR EOT");
|
||||
CDMRData rx_dmrdata;
|
||||
unsigned int n_dmr = (dmr_cnt - 3U) % 6U;
|
||||
unsigned int fill = (6U - n_dmr);
|
||||
|
||||
if (n_dmr) {
|
||||
for (unsigned int i = 0U; i < fill; i++) {
|
||||
|
||||
CDMREMB emb;
|
||||
CDMRData rx_dmrdata;
|
||||
|
||||
rx_dmrdata.setSlotNo(2U);
|
||||
rx_dmrdata.setSrcId(m_dmrSrc);
|
||||
rx_dmrdata.setDstId(m_dstid);
|
||||
rx_dmrdata.setFLCO(m_dmrflco);
|
||||
rx_dmrdata.setN(n_dmr);
|
||||
rx_dmrdata.setSeqNo(dmr_cnt);
|
||||
rx_dmrdata.setBER(0U);
|
||||
rx_dmrdata.setRSSI(0U);
|
||||
rx_dmrdata.setDataType(DT_VOICE);
|
||||
|
||||
::memcpy(m_dmrFrame, DMR_SILENCE_DATA, DMR_FRAME_LENGTH_BYTES);
|
||||
|
||||
// Generate the Embedded LC
|
||||
unsigned char lcss = m_EmbeddedLC.getData(m_dmrFrame, n_dmr);
|
||||
|
||||
// Generate the EMB
|
||||
emb.setColorCode(m_colorcode);
|
||||
emb.setLCSS(lcss);
|
||||
emb.getData(m_dmrFrame);
|
||||
|
||||
rx_dmrdata.setData(m_dmrFrame);
|
||||
|
||||
//CUtils::dump(1U, "DMR data:", m_dmrFrame, 33U);
|
||||
m_dmrNetwork->write(rx_dmrdata);
|
||||
|
||||
n_dmr++;
|
||||
dmr_cnt++;
|
||||
//m_p25Frames = 0;
|
||||
}
|
||||
}
|
||||
|
||||
rx_dmrdata.setSlotNo(2U);
|
||||
rx_dmrdata.setSrcId(m_dmrSrc);
|
||||
rx_dmrdata.setDstId(m_dstid);
|
||||
rx_dmrdata.setFLCO(m_dmrflco);
|
||||
rx_dmrdata.setN(n_dmr);
|
||||
rx_dmrdata.setSeqNo(dmr_cnt);
|
||||
rx_dmrdata.setBER(0U);
|
||||
rx_dmrdata.setRSSI(0U);
|
||||
rx_dmrdata.setDataType(DT_TERMINATOR_WITH_LC);
|
||||
|
||||
// Add sync
|
||||
CSync::addDMRDataSync(m_dmrFrame, 0);
|
||||
|
||||
// Add SlotType
|
||||
CDMRSlotType slotType;
|
||||
slotType.setColorCode(m_colorcode);
|
||||
slotType.setDataType(DT_TERMINATOR_WITH_LC);
|
||||
slotType.getData(m_dmrFrame);
|
||||
|
||||
// Full LC
|
||||
CDMRLC dmrLC = CDMRLC(m_dmrflco, m_dmrSrc, m_dstid);
|
||||
CDMRFullLC fullLC;
|
||||
fullLC.encode(dmrLC, m_dmrFrame, DT_TERMINATOR_WITH_LC);
|
||||
|
||||
rx_dmrdata.setData(m_dmrFrame);
|
||||
//CUtils::dump(1U, "DMR data:", m_dmrFrame, 33U);
|
||||
m_dmrNetwork->write(rx_dmrdata);
|
||||
|
||||
dmrWatch.start();
|
||||
}
|
||||
else if(dmrFrameType == TAG_DATA) {
|
||||
LogMessage("Sending DMR Data");
|
||||
CDMREMB emb;
|
||||
CDMRData rx_dmrdata;
|
||||
unsigned int n_dmr = (dmr_cnt - 3U) % 6U;
|
||||
|
||||
rx_dmrdata.setSlotNo(2U);
|
||||
rx_dmrdata.setSrcId(m_dmrSrc);
|
||||
rx_dmrdata.setDstId(m_dstid);
|
||||
rx_dmrdata.setFLCO(m_dmrflco);
|
||||
rx_dmrdata.setN(n_dmr);
|
||||
rx_dmrdata.setSeqNo(dmr_cnt);
|
||||
rx_dmrdata.setBER(0U);
|
||||
rx_dmrdata.setRSSI(0U);
|
||||
|
||||
if (!n_dmr) {
|
||||
rx_dmrdata.setDataType(DT_VOICE_SYNC);
|
||||
// Add sync
|
||||
CSync::addDMRAudioSync(m_dmrFrame, 0U);
|
||||
// Prepare Full LC data
|
||||
CDMRLC dmrLC = CDMRLC(m_dmrflco, m_dmrSrc, m_dstid);
|
||||
// Configure the Embedded LC
|
||||
m_EmbeddedLC.setLC(dmrLC);
|
||||
}
|
||||
else {
|
||||
rx_dmrdata.setDataType(DT_VOICE);
|
||||
// Generate the Embedded LC
|
||||
unsigned char lcss = m_EmbeddedLC.getData(m_dmrFrame, n_dmr);
|
||||
// Generate the EMB
|
||||
emb.setColorCode(m_colorcode);
|
||||
emb.setLCSS(lcss);
|
||||
emb.getData(m_dmrFrame);
|
||||
}
|
||||
|
||||
rx_dmrdata.setData(m_dmrFrame);
|
||||
|
||||
//CUtils::dump(1U, "DMR data:", m_dmrFrame, 33U);
|
||||
m_dmrNetwork->write(rx_dmrdata);
|
||||
|
||||
dmr_cnt++;
|
||||
dmrWatch.start();
|
||||
}
|
||||
}
|
||||
|
||||
while (m_dmrNetwork->read(tx_dmrdata) > 0U) {
|
||||
m_dmrSrc = tx_dmrdata.getSrcId();
|
||||
m_dmrDst = tx_dmrdata.getDstId();
|
||||
|
||||
if(!m_dmrSrc){
|
||||
m_dmrSrc = m_srcHS;
|
||||
}
|
||||
|
||||
memset(m17_src, 0, 10);
|
||||
std::string css = m_dmrlookup->findCS(m_dmrSrc);
|
||||
memcpy(m17_src, css.c_str(), css.size());
|
||||
m17_src[css.size()] = ' ';
|
||||
m17_src[css.size()+1] = 'D';
|
||||
encode_callsign(m17_src);
|
||||
|
||||
|
||||
FLCO netflco = tx_dmrdata.getFLCO();
|
||||
unsigned char DataType = tx_dmrdata.getDataType();
|
||||
|
||||
if (!tx_dmrdata.isMissing()) {
|
||||
networkWatchdog.start();
|
||||
|
||||
if(DataType == DT_TERMINATOR_WITH_LC) {
|
||||
if (m_dmrFrames == 0U) {
|
||||
m_dmrNetwork->reset(2U);
|
||||
networkWatchdog.stop();
|
||||
m_dmrinfo = false;
|
||||
m_firstSync = false;
|
||||
break;
|
||||
}
|
||||
|
||||
LogMessage("DMR received end of voice transmission, %.1f seconds", float(m_dmrFrames) / 16.667F);
|
||||
|
||||
m_conv.putDMREOT();
|
||||
m_dmrNetwork->reset(2U);
|
||||
networkWatchdog.stop();
|
||||
m_dmrFrames = 0U;
|
||||
m_dmrinfo = false;
|
||||
m_firstSync = false;
|
||||
}
|
||||
|
||||
if((DataType == DT_VOICE_LC_HEADER) && (DataType != m_dmrLastDT)) {
|
||||
std::string netSrc = m_dmrlookup->findCS(m_dmrSrc);
|
||||
std::string netDst = (netflco == FLCO_GROUP ? "TG " : "") + m_dmrlookup->findCS(m_dmrDst);
|
||||
|
||||
m_conv.putDMRHeader();
|
||||
LogMessage("DMR header received from %s to %s", netSrc.c_str(), netDst.c_str());
|
||||
|
||||
m_dmrinfo = true;
|
||||
|
||||
m_dmrFrames = 0U;
|
||||
m_firstSync = false;
|
||||
}
|
||||
|
||||
if(DataType == DT_VOICE_SYNC)
|
||||
m_firstSync = true;
|
||||
|
||||
if((DataType == DT_VOICE_SYNC || DataType == DT_VOICE) && m_firstSync) {
|
||||
unsigned char dmr_frame[50];
|
||||
tx_dmrdata.getData(dmr_frame);
|
||||
|
||||
if (!m_dmrinfo) {
|
||||
std::string netSrc = m_dmrlookup->findCS(m_dmrSrc);
|
||||
std::string netDst = (netflco == FLCO_GROUP ? "TG " : "") + m_dmrlookup->findCS(m_dmrDst);
|
||||
|
||||
m_conv.putDMRHeader();
|
||||
LogMessage("DMR late entry from %s to %s", netSrc.c_str(), netDst.c_str());
|
||||
|
||||
m_dmrinfo = true;
|
||||
}
|
||||
|
||||
m_conv.putDMR(dmr_frame);
|
||||
m_dmrFrames++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(DataType == DT_VOICE_SYNC || DataType == DT_VOICE) {
|
||||
unsigned char dmr_frame[50];
|
||||
tx_dmrdata.getData(dmr_frame);
|
||||
m_conv.putDMR(dmr_frame);
|
||||
m_dmrFrames++;
|
||||
}
|
||||
|
||||
networkWatchdog.clock(ms);
|
||||
if (networkWatchdog.hasExpired()) {
|
||||
LogDebug("Network watchdog has expired, %.1f seconds", float(m_dmrFrames) / 16.667F);
|
||||
m_dmrNetwork->reset(2U);
|
||||
networkWatchdog.stop();
|
||||
m_dmrFrames = 0U;
|
||||
m_dmrinfo = false;
|
||||
}
|
||||
}
|
||||
|
||||
m_dmrLastDT = DataType;
|
||||
}
|
||||
|
||||
if (m17Watch.elapsed() > M17_FRAME_PER) {
|
||||
unsigned int m17FrameType = m_conv.getM17(m_m17Frame);
|
||||
|
||||
if(m17FrameType == TAG_HEADER) {
|
||||
m17_cnt = 0U;
|
||||
m17Watch.start();
|
||||
|
||||
streamid = static_cast<uint16_t>((::rand() & 0xFFFF));
|
||||
memcpy(m17_dst, m_m17Ref.c_str(), m_m17Ref.size());
|
||||
m17_dst[9] = 0x00;
|
||||
encode_callsign(m17_dst);
|
||||
|
||||
memcpy(buffer, "M17 ", 4);
|
||||
memcpy(buffer+4, &streamid, 2);
|
||||
memcpy(buffer+6, m17_dst, 6);
|
||||
memcpy(buffer+12, m17_src, 6);
|
||||
buffer[19] = 0x05;
|
||||
memcpy(buffer+36, m_m17Frame, 16);
|
||||
m_m17Network->writeData(buffer, 54U);
|
||||
}
|
||||
else if(m17FrameType == TAG_EOT) {
|
||||
m17_cnt |= 0x8000;
|
||||
memcpy(buffer, "M17 ", 4);
|
||||
memcpy(buffer+4, &streamid, 2);
|
||||
memcpy(buffer+6, m17_dst, 6);
|
||||
memcpy(buffer+12, m17_src, 6);
|
||||
buffer[19] = 0x05;
|
||||
buffer[34] = m17_cnt >> 8;
|
||||
buffer[35] = m17_cnt & 0xff;
|
||||
memcpy(buffer+36, m_m17Frame, 16);
|
||||
m_m17Network->writeData(buffer, 54U);
|
||||
m17Watch.start();
|
||||
}
|
||||
else if(m17FrameType == TAG_DATA) {
|
||||
//CUtils::dump(1U, "M17 Data", m_p25Frame, 11U);
|
||||
m17_cnt++;
|
||||
memcpy(buffer, "M17 ", 4);
|
||||
memcpy(buffer+4, &streamid, 2);
|
||||
memcpy(buffer+6, m17_dst, 6);
|
||||
memcpy(buffer+12, m17_src, 6);
|
||||
buffer[19] = 0x05;
|
||||
buffer[34] = m17_cnt >> 8;
|
||||
buffer[35] = m17_cnt & 0xff;
|
||||
memcpy(buffer+36, m_m17Frame, 16);
|
||||
m_m17Network->writeData(buffer, 54U);
|
||||
m17Watch.start();
|
||||
}
|
||||
}
|
||||
|
||||
stopWatch.start();
|
||||
|
||||
pollTimer.clock(ms);
|
||||
if (pollTimer.isRunning() && pollTimer.hasExpired()) {
|
||||
m_m17Network->writePoll();
|
||||
pollTimer.start();
|
||||
}
|
||||
|
||||
if(m_dmrNetwork->clock(ms)){
|
||||
m_xlxConnected = false;
|
||||
}
|
||||
|
||||
if (m_xlxReflectors != NULL)
|
||||
m_xlxReflectors->clock(ms);
|
||||
|
||||
if (ms < 5U) CThread::sleep(5U);
|
||||
}
|
||||
|
||||
m_m17Network->close();
|
||||
m_dmrNetwork->close();
|
||||
delete m_dmrNetwork;
|
||||
delete m_m17Network;
|
||||
|
||||
if (m_xlxReflectors != NULL)
|
||||
delete m_xlxReflectors;
|
||||
|
||||
::LogFinalise();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CM172DMR::createDMRNetwork()
|
||||
{
|
||||
std::string address = m_conf.getDMRNetworkAddress();
|
||||
m_xlxmodule = m_conf.getDMRXLXModule();
|
||||
m_xlxrefl = m_conf.getDMRXLXReflector();
|
||||
unsigned int port = m_conf.getDMRNetworkPort();
|
||||
unsigned int local = m_conf.getDMRNetworkLocal();
|
||||
std::string password = m_conf.getDMRNetworkPassword();
|
||||
bool debug = m_conf.getDMRNetworkDebug();
|
||||
unsigned int jitter = m_conf.getDMRNetworkJitter();
|
||||
bool slot1 = false;
|
||||
bool slot2 = true;
|
||||
bool duplex = false;
|
||||
HW_TYPE hwType = HWT_MMDVM;
|
||||
|
||||
m_srcHS = m_conf.getDMRId();
|
||||
m_colorcode = 1U;
|
||||
|
||||
if (m_xlxmodule.empty()) {
|
||||
m_dstid = m_conf.getDMRDstId();
|
||||
m_dmrpc = m_conf.getDMRPC();
|
||||
}
|
||||
else {
|
||||
const char *xlxmod = m_xlxmodule.c_str();
|
||||
m_dstid = 4000 + xlxmod[0] - 64;
|
||||
m_dmrpc = 0;
|
||||
|
||||
CReflector* reflector = m_xlxReflectors->find(m_xlxrefl);
|
||||
if (reflector == NULL)
|
||||
return false;
|
||||
|
||||
address = reflector->m_address;
|
||||
}
|
||||
|
||||
if (m_srcHS > 99999999U)
|
||||
m_defsrcid = m_srcHS / 100U;
|
||||
else if (m_srcHS > 9999999U)
|
||||
m_defsrcid = m_srcHS / 10U;
|
||||
else
|
||||
m_defsrcid = m_srcHS;
|
||||
|
||||
LogMessage("DMR Network Parameters");
|
||||
LogMessage(" ID: %u", m_srcHS);
|
||||
LogMessage(" Default SrcID: %u", m_defsrcid);
|
||||
if (!m_xlxmodule.empty()) {
|
||||
LogMessage(" XLX Reflector: %d", m_xlxrefl);
|
||||
LogMessage(" XLX Module: %s (%d)", m_xlxmodule.c_str(), m_dstid);
|
||||
}
|
||||
else {
|
||||
LogMessage(" Startup DstID: %s%u", m_dmrpc ? "" : "TG ", m_dstid);
|
||||
LogMessage(" Address: %s", address.c_str());
|
||||
}
|
||||
LogMessage(" Port: %u", port);
|
||||
if (local > 0U)
|
||||
LogMessage(" Local: %u", local);
|
||||
else
|
||||
LogMessage(" Local: random");
|
||||
LogMessage(" Jitter: %ums", jitter);
|
||||
|
||||
m_dmrNetwork = new CDMRNetwork(address, port, local, m_srcHS, password, duplex, VERSION, debug, slot1, slot2, hwType, jitter);
|
||||
|
||||
std::string options = m_conf.getDMRNetworkOptions();
|
||||
if (!options.empty()) {
|
||||
LogMessage(" Options: %s", options.c_str());
|
||||
m_dmrNetwork->setOptions(options);
|
||||
}
|
||||
|
||||
unsigned int rxFrequency = m_conf.getRxFrequency();
|
||||
unsigned int txFrequency = m_conf.getTxFrequency();
|
||||
unsigned int power = m_conf.getPower();
|
||||
float latitude = m_conf.getLatitude();
|
||||
float longitude = m_conf.getLongitude();
|
||||
int height = m_conf.getHeight();
|
||||
std::string location = m_conf.getLocation();
|
||||
std::string description = m_conf.getDescription();
|
||||
std::string url = m_conf.getURL();
|
||||
|
||||
LogMessage("Info Parameters");
|
||||
LogMessage(" Callsign: %s", m_callsign.c_str());
|
||||
LogMessage(" RX Frequency: %uHz", rxFrequency);
|
||||
LogMessage(" TX Frequency: %uHz", txFrequency);
|
||||
LogMessage(" Power: %uW", power);
|
||||
LogMessage(" Latitude: %fdeg N", latitude);
|
||||
LogMessage(" Longitude: %fdeg E", longitude);
|
||||
LogMessage(" Height: %um", height);
|
||||
LogMessage(" Location: \"%s\"", location.c_str());
|
||||
LogMessage(" Description: \"%s\"", description.c_str());
|
||||
LogMessage(" URL: \"%s\"", url.c_str());
|
||||
|
||||
m_dmrNetwork->setConfig(m_callsign, rxFrequency, txFrequency, power, m_colorcode, latitude, longitude, height, location, description, url);
|
||||
|
||||
bool ret = m_dmrNetwork->open();
|
||||
if (!ret) {
|
||||
delete m_dmrNetwork;
|
||||
m_dmrNetwork = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_dmrNetwork->enable(true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CM172DMR::writeXLXLink(unsigned int srcId, unsigned int dstId, CDMRNetwork* network)
|
||||
{
|
||||
assert(network != NULL);
|
||||
|
||||
unsigned int streamId = ::rand() + 1U;
|
||||
|
||||
CDMRData data;
|
||||
|
||||
data.setSlotNo(XLX_SLOT);
|
||||
data.setFLCO(FLCO_USER_USER);
|
||||
data.setSrcId(srcId);
|
||||
data.setDstId(dstId);
|
||||
data.setDataType(DT_VOICE_LC_HEADER);
|
||||
data.setN(0U);
|
||||
data.setStreamId(streamId);
|
||||
|
||||
unsigned char buffer[DMR_FRAME_LENGTH_BYTES];
|
||||
|
||||
CDMRLC lc;
|
||||
lc.setSrcId(srcId);
|
||||
lc.setDstId(dstId);
|
||||
lc.setFLCO(FLCO_USER_USER);
|
||||
|
||||
CDMRFullLC fullLC;
|
||||
fullLC.encode(lc, buffer, DT_VOICE_LC_HEADER);
|
||||
|
||||
CDMRSlotType slotType;
|
||||
slotType.setColorCode(XLX_COLOR_CODE);
|
||||
slotType.setDataType(DT_VOICE_LC_HEADER);
|
||||
slotType.getData(buffer);
|
||||
|
||||
CSync::addDMRDataSync(buffer, true);
|
||||
|
||||
data.setData(buffer);
|
||||
|
||||
for (unsigned int i = 0U; i < 3U; i++) {
|
||||
data.setSeqNo(i);
|
||||
network->write(data);
|
||||
}
|
||||
|
||||
data.setDataType(DT_TERMINATOR_WITH_LC);
|
||||
|
||||
fullLC.encode(lc, buffer, DT_TERMINATOR_WITH_LC);
|
||||
|
||||
slotType.setDataType(DT_TERMINATOR_WITH_LC);
|
||||
slotType.getData(buffer);
|
||||
|
||||
data.setData(buffer);
|
||||
|
||||
for (unsigned int i = 0U; i < 2U; i++) {
|
||||
data.setSeqNo(i + 3U);
|
||||
network->write(data);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright (C) 2016 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||
* Copyright (C) 2020 by Doug McLain AD8DP
|
||||
*
|
||||
* 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(P252DMR_H)
|
||||
#define P252DMR_H
|
||||
|
||||
#include "DMRDefines.h"
|
||||
#include "ModeConv.h"
|
||||
#include "DMRNetwork.h"
|
||||
#include "M17Network.h"
|
||||
#include "DMREmbeddedData.h"
|
||||
#include "DMRLC.h"
|
||||
#include "DMRFullLC.h"
|
||||
#include "DMREMB.h"
|
||||
#include "DMRLookup.h"
|
||||
#include "Reflectors.h"
|
||||
#include "UDPSocket.h"
|
||||
#include "StopWatch.h"
|
||||
#include "Version.h"
|
||||
#include "Thread.h"
|
||||
#include "Timer.h"
|
||||
#include "Sync.h"
|
||||
#include "Utils.h"
|
||||
#include "Conf.h"
|
||||
#include "Log.h"
|
||||
#include "CRC.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
enum TG_STATUS {
|
||||
NONE,
|
||||
WAITING_UNLINK,
|
||||
SEND_REPLY,
|
||||
SEND_PTT
|
||||
};
|
||||
|
||||
class CM172DMR
|
||||
{
|
||||
public:
|
||||
CM172DMR(const std::string& configFile);
|
||||
~CM172DMR();
|
||||
|
||||
int run();
|
||||
|
||||
private:
|
||||
std::string m_callsign;
|
||||
std::string m_m17Ref;
|
||||
CConf m_conf;
|
||||
CDMRNetwork* m_dmrNetwork;
|
||||
CM17Network* m_m17Network;
|
||||
CDMRLookup* m_dmrlookup;
|
||||
CModeConv m_conv;
|
||||
unsigned int m_colorcode;
|
||||
unsigned int m_srcHS;
|
||||
unsigned int m_defsrcid;
|
||||
unsigned int m_dstid;
|
||||
bool m_dmrpc;
|
||||
unsigned int m_dmrSrc;
|
||||
unsigned int m_dmrDst;
|
||||
std::string m_m17Src;
|
||||
std::string m_m17Dst;
|
||||
unsigned char m_dmrLastDT;
|
||||
unsigned char* m_m17Frame;
|
||||
unsigned int m_m17Frames;
|
||||
unsigned char* m_dmrFrame;
|
||||
unsigned int m_dmrFrames;
|
||||
CDMREmbeddedData m_EmbeddedLC;
|
||||
FLCO m_dmrflco;
|
||||
bool m_dmrinfo;
|
||||
std::string m_xlxmodule;
|
||||
bool m_xlxConnected;
|
||||
CReflectors* m_xlxReflectors;
|
||||
unsigned int m_xlxrefl;
|
||||
bool m_firstSync;
|
||||
|
||||
bool createDMRNetwork();
|
||||
void writeXLXLink(unsigned int srcId, unsigned int dstId, CDMRNetwork* network);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,48 @@
|
|||
[Info]
|
||||
RXFrequency=435000000
|
||||
TXFrequency=435000000
|
||||
Power=1
|
||||
Latitude=0.0
|
||||
Longitude=0.0
|
||||
Height=0
|
||||
Location=Nowhere
|
||||
Description=Multi-Mode Repeater
|
||||
URL=www.google.co.uk
|
||||
|
||||
[M17 Network]
|
||||
Callsign=AD8DP D
|
||||
LocalPort=32010
|
||||
DstName=M17-BRO A
|
||||
#DstAddress=3.138.122.152
|
||||
DstAddress=192.168.1.8
|
||||
DstPort=17000
|
||||
GainAdjustdB=-6
|
||||
Daemon=0
|
||||
Debug=1
|
||||
|
||||
[DMR Network]
|
||||
Id=3126482
|
||||
#XLXFile=XLXHosts.txt
|
||||
#XLXReflector=950
|
||||
#XLXModule=D
|
||||
StartupDstId=4003
|
||||
# For TG call: StartupPC=0
|
||||
StartupPC=0
|
||||
Address=xlx625.wa8bro.com
|
||||
Port=62030
|
||||
Jitter=500
|
||||
# Local=62032
|
||||
Password=PASSWORD
|
||||
# Options=
|
||||
Debug=1
|
||||
|
||||
[DMR Id Lookup]
|
||||
File=DMRIds.dat
|
||||
Time=24
|
||||
|
||||
[Log]
|
||||
# Logging levels, 0=No logging
|
||||
DisplayLevel=1
|
||||
FileLevel=1
|
||||
FilePath=.
|
||||
FileRoot=M172DMR
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2014,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 "M17Network.h"
|
||||
#include "Utils.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
CM17Network::CM17Network(const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, unsigned char* callsign, bool debug) :
|
||||
m_address(),
|
||||
m_port(gatewayPort),
|
||||
//m_socket(localAddress, localPort),
|
||||
m_socket(localPort),
|
||||
m_debug(debug)
|
||||
{
|
||||
memcpy(m_callsign, callsign, 6);
|
||||
m_address = CUDPSocket::lookup(gatewayAddress);
|
||||
}
|
||||
|
||||
CM17Network::~CM17Network()
|
||||
{
|
||||
}
|
||||
|
||||
bool CM17Network::open()
|
||||
{
|
||||
LogInfo("Opening M17 network connection");
|
||||
|
||||
return m_socket.open();
|
||||
}
|
||||
|
||||
bool CM17Network::writeData(const unsigned char* data, unsigned int length)
|
||||
{
|
||||
assert(data != NULL);
|
||||
assert(length > 0U);
|
||||
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "M17 Network Data Sent", data, length);
|
||||
|
||||
return m_socket.write(data, length, m_address, m_port);
|
||||
}
|
||||
|
||||
bool CM17Network::writePoll()
|
||||
{
|
||||
unsigned char data[10U];
|
||||
|
||||
memcpy(data, "PONG", 4);
|
||||
memcpy(data+4, m_callsign, 6);
|
||||
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "M17 Network Pong Sent", data, 10U);
|
||||
|
||||
return m_socket.write(data, 10U, m_address, m_port);
|
||||
}
|
||||
|
||||
bool CM17Network::writeLink(char m)
|
||||
{
|
||||
unsigned char data[11U];
|
||||
|
||||
memcpy(data, "CONN", 4);
|
||||
memcpy(data+4, m_callsign, 6);
|
||||
data[10U] = m;
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "M17 Network Link Sent", data, 11U);
|
||||
|
||||
//LogInfo("writeLink add:port == %x, %x", m_address.s_addr, m_port);
|
||||
return m_socket.write(data, 11U, m_address, m_port);
|
||||
}
|
||||
|
||||
bool CM17Network::writeUnlink()
|
||||
{
|
||||
unsigned char data[10U];
|
||||
|
||||
memcpy(data, "DISC", 4);
|
||||
memcpy(data+4, m_callsign, 6);
|
||||
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "M17 Network Unlink Sent", data, 10U);
|
||||
|
||||
return m_socket.write(data, 10U, m_address, m_port);
|
||||
}
|
||||
|
||||
unsigned int CM17Network::readData(unsigned char* data, unsigned int length)
|
||||
{
|
||||
assert(data != NULL);
|
||||
assert(length > 0U);
|
||||
|
||||
in_addr address;
|
||||
unsigned int port;
|
||||
int len = m_socket.read(data, length, address, port);
|
||||
if (len <= 0)
|
||||
return 0U;
|
||||
|
||||
// Check if the data is for us
|
||||
if (m_address.s_addr != address.s_addr || port != m_port) {
|
||||
LogMessage("M17 packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, m_port, port);
|
||||
return 0U;
|
||||
}
|
||||
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "M17 Network Data Received", data, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void CM17Network::close()
|
||||
{
|
||||
m_socket.close();
|
||||
|
||||
LogInfo("Closing P25 network connection");
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2014,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 M17Network_H
|
||||
#define M17Network_H
|
||||
|
||||
#include "UDPSocket.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
class CM17Network {
|
||||
public:
|
||||
CM17Network(const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, unsigned char* callsign, bool debug);
|
||||
~CM17Network();
|
||||
|
||||
bool open();
|
||||
bool writeData(const unsigned char* data, unsigned int length);
|
||||
unsigned int readData(unsigned char* data, unsigned int length);
|
||||
bool writePoll();
|
||||
bool writeLink(char m);
|
||||
bool writeUnlink();
|
||||
void close();
|
||||
private:
|
||||
in_addr m_address;
|
||||
unsigned int m_port;
|
||||
CUDPSocket m_socket;
|
||||
bool m_debug;
|
||||
unsigned char m_callsign[6];
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (C) 2016,2017 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||
* Copyright (C) 2020 by Doug McLain AD8DP
|
||||
*
|
||||
* 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 <cstring>
|
||||
#include <md380_vocoder.h>
|
||||
#include "MBEVocoder.h"
|
||||
|
||||
|
||||
const uint8_t BIT_MASK_TABLE8[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U };
|
||||
#define WRITE_BIT8(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE8[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE8[(i)&7])
|
||||
#define READ_BIT8(p,i) (p[(i)>>3] & BIT_MASK_TABLE8[(i)&7])
|
||||
|
||||
MBEVocoder::MBEVocoder(void)
|
||||
{
|
||||
}
|
||||
|
||||
void MBEVocoder::decode_2450(int16_t *pcm, uint8_t *ambe49)
|
||||
{
|
||||
md380_decode(ambe49, pcm);
|
||||
}
|
||||
|
||||
void MBEVocoder::encode_2450(int16_t *pcm, uint8_t *ambe49)
|
||||
{
|
||||
md380_encode(ambe49, pcm);
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (C) 2016,2017 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||
* Copyright (C) 2020 by Doug McLain AD8DP
|
||||
*
|
||||
* 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 INCLUDED_AMBE_ENCODER_H
|
||||
#define INCLUDED_AMBE_ENCODER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
class MBEVocoder {
|
||||
public:
|
||||
void decode_2450(int16_t *, uint8_t *);
|
||||
void encode_2450(int16_t *, uint8_t *);
|
||||
MBEVocoder(void);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#endif /* INCLUDED_AMBE_ENCODER_H */
|
|
@ -0,0 +1,26 @@
|
|||
CC ?= gcc
|
||||
CXX ?= g++
|
||||
CFLAGS ?= -g -O3 -Wall -std=c++0x -pthread
|
||||
LIBS = -lm -lpthread -lmd380_vocoder
|
||||
LDFLAGS ?= -g
|
||||
|
||||
OBJECTS = BPTC19696.o Conf.o CRC.o DelayBuffer.o DMRData.o DMREMB.o DMREmbeddedData.o \
|
||||
DMRFullLC.o DMRLC.o DMRLookup.o DMRNetwork.o DMRSlotType.o M17Network.o Golay2087.o \
|
||||
Golay24128.o Hamming.o Log.o ModeConv.o Mutex.o QR1676.o RS129.o SHA256.o StopWatch.o \
|
||||
Sync.o Thread.o Timer.o UDPSocket.o Utils.o MBEVocoder.o Reflectors.o codec2/codebooks.o codec2/kiss_fft.o \
|
||||
codec2/lpc.o codec2/nlp.o codec2/pack.o codec2/qbase.o codec2/quantise.o codec2/codec2.o M172DMR.o
|
||||
|
||||
all: M172DMR
|
||||
|
||||
M172DMR: $(OBJECTS)
|
||||
$(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o M172DMR -Xlinker --section-start=.firmware=0x0800C000 -Xlinker --section-start=.sram=0x20000000
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
install:
|
||||
install -m 755 M172DMR /usr/local/bin/
|
||||
|
||||
clean:
|
||||
$(RM) M172DMR *.o *.d *.bak *~
|
||||
|
|
@ -0,0 +1,781 @@
|
|||
/*
|
||||
* Copyright (C) 2010,2014,2016,2018 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2016 Mathias Weyland, HB9FRV
|
||||
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||
* Copyright (C) 2020 by Doug McLain AD8DP
|
||||
*
|
||||
* 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 "ModeConv.h"
|
||||
#include "Golay24128.h"
|
||||
#include "Utils.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U };
|
||||
|
||||
#define WRITE_BIT(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7])
|
||||
#define READ_BIT(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
|
||||
|
||||
const unsigned int PRNG_TABLE[] = {
|
||||
0x42CC47U, 0x19D6FEU, 0x304729U, 0x6B2CD0U, 0x60BF47U, 0x39650EU, 0x7354F1U, 0xEACF60U, 0x819C9FU, 0xDE25CEU,
|
||||
0xD7B745U, 0x8CC8B8U, 0x8D592BU, 0xF71257U, 0xBCA084U, 0xA5B329U, 0xEE6AFAU, 0xF7D9A7U, 0xBCC21CU, 0x4712D9U,
|
||||
0x4F2922U, 0x14FA37U, 0x5D43ECU, 0x564115U, 0x299A92U, 0x20A9EBU, 0x7B707DU, 0x3BE3A4U, 0x20D95BU, 0x6B085AU,
|
||||
0x5233A5U, 0x99A474U, 0xC0EDCBU, 0xCB5F12U, 0x918455U, 0xF897ECU, 0xE32E3BU, 0xAA7CC2U, 0xB1E7C9U, 0xFC561DU,
|
||||
0xA70DE6U, 0x8DBE73U, 0xD4F608U, 0x57658DU, 0x0E5E56U, 0x458DABU, 0x7E15B8U, 0x376645U, 0x2DFD86U, 0x64EC3BU,
|
||||
0x3F1F60U, 0x3481B4U, 0x4DA00FU, 0x067BCEU, 0x1B68B1U, 0xD19328U, 0xCA03FFU, 0xA31856U, 0xF8EB81U, 0xF9F2F8U,
|
||||
0xA26067U, 0xA91BB6U, 0xF19A59U, 0x9A6148U, 0x8372B6U, 0xC8E86FU, 0x9399DCU, 0x1A0291U, 0x619142U, 0x6DE9FFU,
|
||||
0x367A2CU, 0x7D2511U, 0x6484DAU, 0x2F1F0FU, 0x1E6DB4U, 0x55F6E1U, 0x0EA70AU, 0x061C96U, 0xDD0E45U, 0xB4D738U,
|
||||
0xAF64ABU, 0xE47F42U, 0xFDBE9DU, 0xB684ACU, 0xFE5773U, 0xC1E4A2U, 0x8AFD0DU, 0x932ED4U, 0xD814E3U, 0x81853AU,
|
||||
0x225EECU, 0x7A6945U, 0x31A112U, 0x2AB2EBU, 0x630974U, 0x785AB5U, 0x11E3CEU, 0x4A715BU, 0x402AA0U, 0x199B7DU,
|
||||
0x16C05EU, 0x6F5283U, 0xA4FB10U, 0xBFA8ECU, 0xF633B7U, 0xEC4012U, 0xADD8C9U, 0xD6EB1CU, 0xDD3027U, 0x84A1FAU,
|
||||
0xCF9E19U, 0xD64C80U, 0xBC4557U, 0xA7B62EU, 0x6E2DA1U, 0x311F50U, 0x38C68EU, 0x63D5BFU, 0x486E60U, 0x10BFE1U,
|
||||
0x5BAD1EU, 0x4A4647U, 0x0157F0U, 0x7ACC29U, 0x73BEEAU, 0x2825D7U, 0xA0940CU, 0xFBCFF9U, 0xB05C62U, 0x892426U,
|
||||
0xC6B3DDU, 0xDF3840U, 0x9449B3U, 0xCED3BEU, 0xE7804DU, 0xBC3B90U, 0xF5AA0BU, 0xE6D17EU, 0x2D43B5U, 0x345A04U,
|
||||
0x5EA9DBU, 0x07A202U, 0x0C7134U, 0x45C9FDU, 0x5EDA0AU, 0x310193U, 0x6830C4U, 0x62AA3DU, 0x3B59B2U, 0xB04043U,
|
||||
0xEB975CU, 0x82BCADU, 0x912E62U, 0xD8F7FBU, 0x82C489U, 0x895F54U, 0xF00FE7U, 0xFBBC2AU, 0xA2E771U, 0xE956C4U,
|
||||
0xF6CD1FU, 0x3F8FEAU, 0x0534E1U, 0x4C653CU, 0x17FE8FU, 0x1C4C52U, 0x4515A1U, 0x2E86A9U, 0x3FBD56U, 0x756C87U,
|
||||
0x6ED218U, 0x279179U, 0x7C0AA6U, 0xD53B17U, 0x8EE0C8U, 0x85F291U, 0xD94B36U, 0x9298EFU, 0xAB8318U, 0xE07301U,
|
||||
0xBB68DFU, 0xB2CB7CU, 0xE910A5U, 0xE101D2U, 0x92BB4BU, 0x59E8B4U, 0x407175U, 0x0B026AU, 0x12989BU, 0x792944U,
|
||||
0x2376EDU, 0x2EF5BAU, 0x758663U, 0x7C1ED5U, 0x078D0CU, 0x4EF6ABU, 0x5567F2U, 0x9F7C29U, 0xC68E9CU, 0xC51747U,
|
||||
0xBC6422U, 0xB7EFB9U, 0xECFD44U, 0xA50497U, 0xAF178AU, 0xD68C69U, 0xD97DB5U, 0x82670EU, 0xCBB45BU, 0x508D90U,
|
||||
0x190A25U, 0x63F0FEU, 0x68E3C7U, 0x317A10U, 0x3A09D9U, 0x6B926EU, 0x004237U, 0x1B79C8U, 0x53EA59U, 0x48B3B7U,
|
||||
0x811166U, 0xDE4A79U, 0xF5F988U, 0xAC6057U, 0xE733FEU, 0xFF89ADU, 0xB49830U, 0x8F4BC3U, 0xC6F00EU, 0x9DA135U,
|
||||
0x942FE0U, 0xC71C3BU, 0x4DC78FU, 0x3476C4U, 0x7F6C39U, 0x66BFAAU, 0x298657U, 0x725504U, 0x5B4E89U, 0x01FE72U,
|
||||
0x0835A3U, 0x53269CU, 0x189D4DU, 0x01CDC2U, 0xEA763BU, 0xF3A56DU, 0xB0BCD4U, 0xE80F13U, 0xE355CAU, 0x98C47DU,
|
||||
0x91AB24U, 0xCE38DBU, 0x87A35AU, 0x9CD3A5U, 0xD648F4U, 0xAF7B6FU, 0x24A292U, 0x7D3011U, 0x764B6DU, 0x2DDABEU,
|
||||
0x44D123U, 0x5E22D8U, 0x1FB09DU, 0x04A926U, 0x4F5AF3U, 0x064128U, 0x3DB105U, 0x70AAD6U, 0xAA392FU, 0xA1C4B8U,
|
||||
0xF8C7C0U, 0xD35D0FU, 0x8A2E9EU, 0xC1B761U, 0xDA44F0U, 0x925E8FU, 0x89CF4EU, 0xE8B4D1U, 0xB32728U, 0xB8FE7FU,
|
||||
0x61DCC6U, 0x2A4701U, 0x1614D8U, 0x5DADE2U, 0x46BE37U, 0x0F44DCU, 0x54D549U, 0x5D8E32U, 0x263DAFU, 0x2C237CU,
|
||||
0x75E291U, 0xBE5982U, 0xA74A7FU, 0xC493A4U, 0xDFA131U, 0x967A5AU, 0xCCCB8EU, 0xC1D835U, 0x9A02ECU, 0xF331BBU,
|
||||
0xE8B812U, 0xA3EBC5U, 0xBA507CU, 0x7080ABU, 0x099BC2U, 0x02285DU, 0x59718CU, 0x50C273U, 0x0B1862U, 0x4A1F8CU,
|
||||
0x70A655U, 0x3BF5C2U, 0x666FBBU, 0x6DDE68U, 0x3485C5U, 0x9F161EU, 0xC46F4BU, 0x8CFDF0U, 0x97C625U, 0xDE058EU,
|
||||
0xC59CD3U, 0xAEAE20U, 0xF775BCU, 0xFC647FU, 0xBD9F02U, 0xE70C91U, 0xCC1468U, 0x11E7B7U, 0x1AFC36U, 0x435B49U,
|
||||
0x080398U, 0x139027U, 0x7B63FEU, 0x607AF9U, 0x29E900U, 0x7293D6U, 0x79026FU, 0x00D930U, 0x0BEAF1U, 0xD3614EU,
|
||||
0x90119FU, 0x8B8AE4U, 0xC61969U, 0xBD609AU, 0xB4F247U, 0xEFA954U, 0xE518A9U, 0xBC0362U, 0xD7D0D6U, 0xCE7E8DU,
|
||||
0x856F18U, 0x1C94E3U, 0x578726U, 0x0D5F1DU, 0x24ECC0U, 0x7FF713U, 0x3E26AAU, 0x251D6DU, 0x6A8F14U, 0x53648BU,
|
||||
0x19757AU, 0x40AEB4U, 0xCB9CA5U, 0x90055AU, 0x9956C3U, 0xE2ED34U, 0xAB3C7DU, 0xB126EAU, 0xFA9513U, 0xA3D2C8U,
|
||||
0x886BFDU, 0xD9F836U, 0xD2A2E3U, 0x8D1359U, 0x454804U, 0x5EDBF7U, 0x37637AU, 0x2C3089U, 0x67ABD4U, 0x3E8847U,
|
||||
0x3551BAU, 0x4D6331U, 0x46B8C4U, 0x1D299FU, 0x54120EU, 0x5FC0E1U, 0x86D93BU, 0xE56A0EU, 0xFBB1D5U, 0xB2B600U,
|
||||
0xA94EABU, 0xE05DF6U, 0x9BE605U, 0x90B798U, 0xC92C6BU, 0xC3DE66U, 0x9AC7BDU, 0xD15448U, 0x6A3FD3U, 0x23ADA3U,
|
||||
0x78346CU, 0x7147F5U, 0x2BDC02U, 0x0EAD5BU, 0x553FFCU, 0x1EA425U, 0x07D5F2U, 0x4C4ECBU, 0x554C14U, 0x3EB3F5U,
|
||||
0xE4A26AU, 0xED799BU, 0xB6CA85U, 0xFFD25CU, 0xC421BFU, 0x8F3A22U, 0x96AB51U, 0xDC518CU, 0x895217U, 0x8289F2U,
|
||||
0xF9B8A9U, 0xF0231CU, 0x2BF1C7U, 0x62C80AU, 0x781B39U, 0x1320E5U, 0x4AB156U, 0x41EB8FU, 0x1848E0U, 0x13D771U,
|
||||
0x4886AEU, 0x203C5FU, 0x3B6F40U, 0x76F6A1U, 0xE5457EU, 0xAE1EE7U, 0xD7AC10U, 0xDCB549U, 0x8476EFU, 0x8FC536U,
|
||||
0xD49DE9U, 0x9D0ED8U, 0xA63513U, 0xEFE4A6U, 0xB4DF7DU, 0x3E0D00U, 0x779693U, 0x4CA75EU, 0x0568ADU, 0x527BB0U,
|
||||
0x59C34BU, 0x00109FU, 0x0A0B14U, 0x73FA61U, 0x38E0BAU, 0x23530FU, 0x6A88D4U, 0xB199DDU, 0x98322AU, 0xC260F3U,
|
||||
0xCBF944U, 0x908A0DU, 0xDB11F2U, 0xC28163U, 0xADFABDU, 0xBC694CU, 0xF65243U, 0xAD83BAU, 0xA40D6DU, 0x5F7EF4U,
|
||||
0x16E787U, 0x0DF44AU, 0x460EF1U, 0x5E1F24U, 0x15CC3FU, 0x6C77CAU, 0x676401U, 0x3C9CBDU, 0x359FEEU, 0x6A0413U,
|
||||
0x02F590U, 0x91EE4DU, 0xDA3C3EU, 0xC305A3U, 0x889658U, 0xF14D99U, 0xFA7F86U, 0xA1E677U, 0xE981E8U, 0xF21A10U,
|
||||
0xBB4BD7U, 0x80F1CEU, 0xCB6239U, 0x123BE0U, 0x1D885FU, 0x45921EU, 0x6641E1U, 0x3DE870U, 0x74BBAFU, 0x6F00C6U,
|
||||
0x261055U, 0x7DCBA8U, 0x57787AU, 0x0E2167U, 0x05B28CU, 0xCC8819U, 0x975BE2U, 0xBC52B7U, 0xE5E52CU, 0xEB37C9U,
|
||||
0xB20E12U, 0xF9DD2FU, 0xE8C6FCU, 0x837701U, 0xD8AD82U, 0xD1BE5AU, 0x0B0525U, 0x0244B4U, 0x79FE5BU, 0x322DCAU,
|
||||
0x2B3495U, 0x60876CU, 0x79DCFBU, 0x334C12U, 0x4C7745U, 0x45A4DCU, 0x1E3F23U, 0x175FF2U, 0xC4C0D8U, 0xAFF30DU,
|
||||
0xB72AF6U, 0xFCB96BU, 0xA5C338U, 0xAE5295U, 0xF54946U, 0xDCBABBU, 0x87A1A8U, 0xCF2165U, 0xD4DA9EU, 0x9FC90BU,
|
||||
0x223070U, 0x6922A4U, 0x30B92FU, 0x3348D6U, 0x695B01U, 0x20C038U, 0x1BB2EFU, 0x523B06U, 0x49EC99U, 0x02D7C8U,
|
||||
0x5B4777U, 0x713CA6U, 0xA8AF49U, 0xA3B650U, 0xF84586U, 0xB5DF7FU, 0xAE8CF8U, 0xC72581U, 0x9D3652U, 0x9EEDCFU,
|
||||
0xC75D34U, 0xCC0671U, 0xB5B5CAU, 0xFEAC1FU, 0x677EA4U, 0x2DC5F9U, 0x26D63AU, 0x7F1F86U, 0x142855U, 0x0DF2A8U,
|
||||
0x42E3B3U, 0x195872U, 0x108B8DU, 0x6AB31CU, 0x632063U, 0x307BAAU, 0xFBC83DU, 0xE201C4U, 0xA91393U, 0x90A82AU,
|
||||
0xDAF9E4U, 0x816A55U, 0x88D00AU, 0xD383DBU, 0xFA3A64U, 0xA569A5U, 0xEEE2DEU, 0x76D243U, 0x3D0D90U, 0x649E6DU,
|
||||
0x47E76EU, 0x1C7491U, 0x156E49U, 0x4E9DDEU, 0x0604B7U, 0x3D3720U, 0x76FDD9U, 0x6FEC06U, 0x2417B7U, 0xFD04F8U,
|
||||
0xF29D29U, 0x886F92U, 0xC1744FU, 0xDAC73CU, 0x939EB1U, 0x880C63U, 0xEBE79EU, 0xB2F285U, 0xB86970U, 0xE11ABBU,
|
||||
0xEA822EU, 0x311155U, 0x586AC0U, 0x43F92BU, 0x0A81F6U, 0x5412C5U, 0x5D111CU, 0x26E8CBU, 0x2D7B63U, 0x74213CU,
|
||||
0x3F90CDU, 0x2E8B52U, 0x645883U, 0xDFE36CU, 0x96F375U, 0xDD0882U, 0xC40B1BU, 0x8FD6CCU, 0xB464A5U, 0xFC7F3EU,
|
||||
0xA7AECBU, 0xAA9511U, 0xF10634U, 0xBA5CEFU, 0x83ED32U, 0x483681U, 0x5015DCU, 0x138D3FU, 0x48DEA2U, 0x616571U,
|
||||
0x3AF40CU, 0x33AF97U, 0x681D72U, 0x2246E9U, 0x3BD7B9U, 0x506C46U, 0x0D2FDFU, 0x869338U, 0xDDC061U, 0xD45BD6U,
|
||||
0xAF6A0FU, 0xE7B8C0U, 0xFC2371U, 0xBF102EU, 0xA6C9DFU, 0xEDDA40U, 0x943089U, 0x9FA1BFU, 0x459A66U, 0x0C4995U,
|
||||
0x175108U, 0x7AE243U, 0x6139B6U, 0x2A2A2DU, 0x73D3D8U, 0x79C183U, 0x204A26U, 0x0B3FFDU, 0x5AA420U, 0x111613U,
|
||||
0x8A4FDFU, 0xC3DC2CU, 0xF9A7B5U, 0xB034EAU, 0xEBAC5BU, 0xE0CF94U, 0xBD5465U, 0xF605FAU, 0xCFBEA3U, 0x85AC54U,
|
||||
0x9E55DDU, 0xD7C62AU, 0x0CDD73U, 0x252FCDU, 0x76361CU, 0x7DF5D3U, 0x3546E2U, 0x6E5B39U, 0x67A98CU, 0x1CB247U,
|
||||
0x57231AU, 0x4AD8A9U, 0x01CA74U, 0x191187U, 0xF2208AU, 0xA9AB50U, 0xA0F8A5U, 0xFB403EU, 0xF2D34BU, 0xA9A880U,
|
||||
0xCB393DU, 0xD262EEU, 0x99D0B7U, 0xC04B00U, 0xCB1AC9U, 0xB0B176U, 0x39E3A7U, 0x677EF8U, 0x2ECD58U, 0x359687U,
|
||||
0x7E277EU, 0x473D69U, 0x0CEEB0U, 0x55D557U, 0x5F04CEU, 0x0C8EBDU, 0x25BD60U, 0x7E64DBU, 0xB7771EU, 0xACCC05U,
|
||||
0xE51CF0U, 0xBF2F2AU, 0x90F497U, 0xC9E7D4U, 0xC25F09U, 0x9B9CBAU, 0xD08767U, 0xEB320CU, 0xA36999U, 0x38FB42U,
|
||||
0x7180B3U, 0x22112CU, 0x29AA45U, 0x50F9D2U, 0x1B610AU, 0x0202FDU, 0x4899E4U, 0x57080BU, 0x3E72DAU, 0x65E165U,
|
||||
0x6CFA34U, 0xB70BEBU, 0xBC104AU, 0xE4E295U, 0x8F7BECU, 0x96787FU, 0xD583B2U, 0x9E9740U, 0x870C5DU, 0xECFFA6U,
|
||||
0xF4E433U, 0xBF35F8U, 0xE00F8DU, 0x699C16U, 0x3265EBU, 0x1B6638U, 0x40F515U, 0x0A8DC6U, 0x131E1BU, 0x5845A0U,
|
||||
0x21F670U, 0x2A6E1FU, 0x791D8EU, 0x708651U, 0x2AD7E8U, 0xE37CAFU, 0xD8EE56U, 0x97B3C1U, 0x8E0018U, 0xC51B6FU,
|
||||
0x9CC9E6U, 0xB67019U, 0xEF23C8U, 0xE498F2U, 0xBF9927U, 0xF643ECU, 0xCD7051U, 0x04E902U, 0x563AFFU, 0x5D006CU,
|
||||
0x04D3A1U, 0x0FCA9AU, 0x72794FU, 0x39A2B4U, 0x228231U, 0x6A19EAU, 0x714E96U, 0x18F705U, 0x4324FCU, 0xC83E3BU,
|
||||
0x918D02U, 0xDADCD5U, 0xC2470CU, 0xA135B3U, 0xBABCF2U, 0xF30F4DU, 0xA8549EU, 0xA1C543U, 0xDEFF78U, 0xD42CBCU,
|
||||
0x0DB747U, 0x46C6D2U, 0x5F5C89U, 0x144F60U, 0x6FA6F7U, 0x66350EU, 0x2C0A59U, 0x35DAE0U, 0x7EC12FU, 0x0D32FEU,
|
||||
0x0429C1U, 0x5FB911U, 0xD642AEU, 0x895167U, 0xC3D8B0U, 0xFAAB89U, 0xB1315AU, 0xA8C0A7U, 0xE3DB24U, 0xB84879U,
|
||||
0x913382U, 0xCBA317U, 0x82F8FCU, 0x994BA9U, 0x50C213U, 0x4390CEU, 0x282F5DU, 0x713E30U, 0x7FCDE3U, 0x26565EU,
|
||||
0x2D0485U, 0x56BDD4U, 0x1FAE7BU, 0x0475AAU, 0x4DD555U, 0x17CE4CU, 0x9C1D9BU, 0xE52473U, 0xEEF7E4U, 0xB7CD1DU,
|
||||
0xF45E42U, 0xEF87E3U, 0x87B43CU, 0x986FADU, 0xD16FD2U, 0x8AD403U, 0x8103A8U, 0xD83A75U, 0x33A826U, 0x2BF39BU,
|
||||
0x604049U, 0x7B99A4U, 0x328ABFU, 0x49306AU, 0x407191U, 0x1BEA04U, 0x19D96FU, 0x4001F2U, 0x0FB201U, 0x36E9DCU,
|
||||
0xFD7ADFU, 0xE64326U, 0xAF91F9U, 0xF51249U, 0xDC2B16U, 0x87F8D7U, 0xCCE668U, 0xC517B1U, 0x9E8C46U, 0x97BF5FU,
|
||||
0xED6498U, 0xA67461U, 0x378FF6U, 0x788C8FU, 0x611514U, 0x0AE6F1U, 0x53FC2BU, 0x596F3EU, 0x0216C5U, 0x4B8508U,
|
||||
0x507FBBU, 0x396EE6U, 0x22F535U, 0xE99688U, 0xB10F43U, 0xBA1D36U, 0xC3E2ADU, 0xC07178U, 0x9B28C3U, 0xD69A8BU,
|
||||
0xCD817CU, 0x8570E5U, 0xFEEB12U, 0xF5E8CBU, 0xAC10C4U, 0x270335U, 0x7ED8EAU, 0x156B5BU, 0x0E7A14U, 0x46A0C5U,
|
||||
0x5D937AU, 0x144AA3U, 0x4F79D5U, 0x6CF35CU, 0x31228FU, 0x7A1932U, 0x628E69U, 0xA9D59CU, 0x926517U, 0xDBBEE2U,
|
||||
0x80ADB9U, 0x891424U, 0xD246D7U, 0xD8ED1AU, 0xA17C28U, 0xEA27F5U, 0xF3942EU, 0xB8CE8FU, 0xAB5FD0U, 0x466461U,
|
||||
0x1CB7BEU, 0x152F6FU, 0x4E1CC0U, 0x05D799U, 0x1CE66EU, 0x773DF7U, 0x7EAB00U, 0x249048U, 0x6D41D7U, 0x765A26U,
|
||||
0x1DA9F9U, 0x8431C8U, 0xCF0203U, 0x96C1DEU, 0x90D86DU, 0xCB6A30U, 0xA23193U, 0xB9A24EU, 0xF05B95U, 0xEB48A0U,
|
||||
0xA0D27AU, 0xD8A39FU, 0xD33804U, 0x0A9B79U, 0x01C3AAU, 0x5A5437U, 0x132FD4U, 0x28BC0DU, 0x60253AU, 0x3F57E3U,
|
||||
0x3CCC7CU, 0x65DD9DU, 0x4E26C2U, 0x172572U, 0xDCDDADU, 0xC64E64U, 0x8F5553U, 0x94A68AU, 0xFDBE7DU, 0xA66DE4U,
|
||||
0xADD68BU, 0xF4C75AU, 0xFE0CC1U, 0x873E34U, 0xC8A72FU, 0xDBD0C2U, 0x124B10U, 0x49998DU, 0x40A8FEU, 0x3A3323U,
|
||||
0x316088U, 0x68D95DU, 0x235B06U, 0x3A00B3U, 0x51B178U, 0x4AEA89U, 0x025816U, 0x59C36FU, 0xD092B8U, 0x8B2930U,
|
||||
0xE43AC7U, 0xF5E2DEU, 0xBEC121U, 0xA71AF0U, 0xED8B7FU, 0x94B40EU, 0x9F66D1U, 0xD45D68U, 0xCD8CBFU, 0x8617F6U,
|
||||
0x5F2545U, 0x75FC98U, 0x2EFF62U, 0x674467U, 0x7C959CU, 0x318F09U, 0x0A7CD2U, 0x4967AFU, 0x11D62CU, 0x1A8CD1U,
|
||||
0x431F02U, 0x48A69DU, 0xB3E5ECU, 0xFA7623U, 0xE10E9AU, 0xA99948U, 0xB20215U, 0xD971A6U, 0x80E86BU, 0x8BDA90U,
|
||||
0xD60185U, 0x9D907EU, 0x8FFBFBU, 0xE66920U, 0x7D705DU, 0x3483CEU, 0x6F9833U, 0x646BF1U, 0x1DF3E8U, 0x17E017U,
|
||||
0x4E1BC6U, 0x050A79U, 0x1E8038U, 0x5773E7U, 0x2C685EU, 0xA1BD89U, 0xFB86B0U, 0xF01477U, 0xA16D8EU, 0xCAFE19U,
|
||||
0xD365C1U, 0x9815AEU, 0x839E3FU, 0xCBCDC4U, 0x907611U, 0xB9E70AU, 0xE2BDE7U, 0x2B0E34U, 0x301789U, 0x7BE4DAU,
|
||||
0x477707U, 0x0C2FACU, 0x558C79U, 0x5E9743U, 0x0D4496U, 0x04786DU, 0x7FABE0U, 0x3730B3U, 0x3C014AU, 0xE7DADDU,
|
||||
0xEEE834U, 0x956163U, 0xDCB2FAU, 0xC78905U, 0x8D5BD4U, 0xD0427BU, 0xDBF12BU, 0xA22AB4U, 0xA93B4DU, 0xFA819AU,
|
||||
0xB3D2B3U, 0x287B64U, 0x40289DU, 0x5BB206U, 0x100153U, 0x495CB8U, 0x42CF2DU, 0x3BF4D6U, 0x70248BU, 0x6ABF19U,
|
||||
0x23CCF4U, 0x3C4527U, 0x75761AU, 0x8EACC1U, 0x853F44U, 0xD44EBFU, 0xDED5EEU, 0x87C751U, 0xEC3E80U, 0xF72D6FU,
|
||||
0xBEB676U, 0xE557A1U, 0xEC4D59U, 0xB6BECEU, 0x9DA527U, 0x443078U, 0x0BCAE9U, 0x12D916U, 0x594087U, 0x6033E8U,
|
||||
0x22A831U, 0x7948A2U, 0x70535FU, 0x2BC01CU, 0x62BBA1U, 0x592A7BU, 0x92308EU, 0x8AC395U, 0xC15A50U, 0x9809ABU,
|
||||
0xB3B336U, 0xECB245U, 0xE54998U, 0xBEDA1BU, 0xF681E6U, 0xED35F5U, 0x8E2E0CU, 0x87FDD3U, 0x5CC453U, 0x1556ACU,
|
||||
0x0E85FDU, 0x64AC42U, 0x3D7F8BU, 0x36447CU, 0x6FD665U, 0x640FB2U, 0x3B3C4BU, 0x52A7C4U, 0x48F7B5U, 0x014C2EU,
|
||||
0x9A9FFBU, 0xD19601U, 0xA0250CU, 0xAB7FFFU, 0xF2C822U, 0xB8D1B1U, 0xA302CCU, 0xEAB907U, 0xD1E9B2U, 0x987269U,
|
||||
0xC3411CU, 0xCC8897U, 0x141A42U, 0x3F61B8U, 0x66F2A1U, 0x2DCB56U, 0x3618DFU, 0x778208U, 0x2CB3F1U, 0x0468EEU,
|
||||
0x5F7B1FU, 0x5693D0U, 0x0D8041U, 0x461B3EU, 0xFFECE7U, 0xB4FD50U, 0xA94798U, 0xE314CFU, 0xB88D76U, 0xB17EADU,
|
||||
0xCA7508U, 0xC3E553U, 0x989EA6U, 0xDB0D3DU, 0xC396E8U, 0xA8E683U, 0x717D1EU, 0x7A0EEDU, 0x219730U, 0x288422U,
|
||||
0x736ECFU, 0x1BFF14U, 0x04A4A1U, 0x4F177AU, 0x56092BU, 0x1DD884U, 0x64635DU, 0xEF70EAU, 0xA589B3U, 0xF49B54U,
|
||||
0xFF50CDU, 0xA66312U, 0x8DFA62U, 0xD628FDU, 0x9F131CU, 0x8582C3U, 0xCCF9DAU, 0xF36A29U, 0xB8B2F4U, 0x618157U,
|
||||
0x6A020AU, 0x335999U, 0x79E864U, 0x4272BFU, 0x03259AU, 0x189C40U, 0x51CFB5U, 0x0A752EU, 0x216463U, 0x79BF90U,
|
||||
0x721C0DU, 0xAB47FEU, 0xE4D727U, 0xFDEC28U, 0x963FD9U, 0x8DA646U, 0xC594B7U, 0x9E4FE8U, 0x977E60U, 0xECA597U,
|
||||
0xAF264EU, 0xB61C79U, 0xFDCDA0U, 0x65D64FU, 0x2E61DCU, 0x553881U, 0x5CAA72U, 0x0351FBU, 0x0A400CU, 0x51FB55U,
|
||||
0x3BB9CAU, 0x22223AU, 0x6993B5U, 0x30C8C4U, 0x3B5B1BU, 0xE02B82U, 0xC1B075U, 0x9B23BCU, 0xD25A8BU, 0xC9C852U,
|
||||
0x82A3A9U, 0xBB303CU, 0xF42977U, 0xADDA82U, 0xA64418U, 0xFC55E5U, 0xB5AEE6U, 0x0EBD3BU, 0x4765C8U, 0x4CD655U,
|
||||
0x17DD2EU, 0x562EEBU, 0x6C3770U, 0x25A585U, 0x3E5EDEU, 0x754F6FU, 0x2C94A1U, 0x23A758U, 0x5A3F4FU, 0xD07C96U,
|
||||
0x8BC761U, 0xC254E8U, 0xD92C97U, 0xB0BF06U, 0xEBE0D9U, 0xE25138U, 0xB8CAA7U, 0xBB98DEU, 0xE22109U, 0x896291U,
|
||||
0x10F172U, 0x5BCB2FU, 0x401A94U, 0x0CA141U, 0x77B2BAU, 0x7E6BBFU, 0x255964U, 0x6E82D9U, 0x77130AU, 0x3C3877U,
|
||||
0x04EAF4U, 0x4FD129U, 0x9C40DBU, 0x959BC6U, 0xCEAC2DU, 0xE774FCU, 0xBC6763U, 0xF6DC12U, 0xEB8DCDU, 0xA00664U,
|
||||
0xF9F4B3U, 0xD2EF4AU, 0x895E5DU, 0x800584U, 0x5A972BU, 0x132EFBU, 0x287D84U, 0x63E615U, 0x7297CEU, 0x391D23U,
|
||||
0x608E30U, 0x6AF5CDU, 0x11641EU, 0x5C5E93U, 0x4789E0U, 0x0E903DU, 0x956386U, 0xFEF053U, 0xB6E879U, 0xAD0BACU,
|
||||
0xE41077U, 0xFF83CAU, 0xB47A99U, 0xCD6870U, 0xCE93E7U, 0x96823EU, 0x9D1941U, 0xC4EBD0U, 0x2BF23FU, 0x3031EEU,
|
||||
0x790A71U, 0x229909U, 0x2AC1CEU, 0x717677U, 0x5AEDA0U, 0x039C99U, 0x480646U, 0x515587U, 0x1AEC3CU, 0x296F69U,
|
||||
0xE13492U, 0xBA8607U, 0xB39FCCU, 0xEC4CB1U, 0xA77723U, 0x9EA7DEU, 0xD51C0DU, 0xCD0F00U, 0x86D4FBU, 0xDDF56EU,
|
||||
0xF46F95U, 0x2FBCD4U, 0x268D6BU, 0x7D52B2U, 0x374165U, 0x26F9DCU, 0x4D2A9BU, 0x141163U, 0x1FD2FCU, 0x40CA2DU,
|
||||
0x497952U, 0x3322D3U, 0x7AB32CU, 0xE108F5U, 0xAA5AE2U, 0xB3E31BU, 0xF8B098U, 0x812B65U, 0x8B8936U, 0xD0D08AU,
|
||||
0xD94341U, 0x8A7894U, 0xE3A9AFU, 0xF8377AU, 0xB74481U, 0x6FDD0CU, 0x64EE5FU, 0x3D35A2U, 0x163731U, 0x5F8ECCU,
|
||||
0x045DC7U, 0x0F4616U, 0x57B6E8U, 0x7CAD79U, 0x253E86U, 0x6EC7CFU, 0x7DD478U, 0xB426A1U, 0xCF2D76U, 0xC3BC5FU,
|
||||
0x984780U, 0x935571U, 0xCACCEEU, 0x81BBBFU, 0xB82054U, 0xF371C0U, 0xE9CB3BU, 0xA05826U, 0xFB33F5U, 0x52A218U,
|
||||
0x09B88BU, 0x424BF6U, 0x53D22DU, 0x198198U, 0x043A53U, 0x6F2A06U, 0x34F1BDU, 0x3DC260U, 0x664982U, 0x6FB81BU,
|
||||
0x15A24CU, 0xDE71F5U, 0xC7482AU, 0x8CDFCBU, 0x9505D4U, 0xDE3405U, 0xA5EFFAU, 0xA4FC63U, 0xFE5704U, 0xB387DDU,
|
||||
0xA8BC6AU, 0xC32FB2U, 0x5A7EE5U, 0x11C44CU, 0x489797U, 0x420E62U, 0x19BD79U, 0x30E6BCU, 0x6B6407U, 0x225DDAU,
|
||||
0x398EA9U, 0x703534U, 0x0A64F7U, 0x09FA0AU, 0xD4C910U, 0xDF10E5U, 0x86833EU, 0xCDB99BU, 0xE67A40U, 0xBE631BU,
|
||||
0xB590AEU, 0xEC8B75U, 0xA73BD0U, 0x9CE08BU, 0xD5F35EU, 0x8E0AE5U, 0x061828U, 0x5D835AU, 0x5660C7U, 0x277914U,
|
||||
0x68CAE9U, 0x7190E2U, 0x3A0113U, 0x20FECCU, 0x49ED7DU, 0x127522U, 0x1B06ABU, 0x40855CU, 0x8B9E85U, 0x926FB2U,
|
||||
0xF8F56AU, 0xE186A5U, 0xAA1F14U, 0xF10CCBU, 0xF0F7BAU, 0x8F6735U, 0x867CECU, 0xDC9F1FU, 0x978402U, 0x8E54F1U,
|
||||
0x45EF3CU, 0x7CFC8FU, 0x3705D2U, 0x6C1248U, 0x64C8BDU, 0x3FF976U, 0x566243U, 0x4DA198U, 0x069B45U, 0x1F0AF6U,
|
||||
0x5851BBU, 0x00E248U, 0xAB3BD1U, 0xF2090EU, 0xF9926FU, 0xA2C3F1U, 0xEB7800U, 0xD07B9FU, 0x98A1E6U, 0xC31021U,
|
||||
0xC84BB8U, 0x91D84FU, 0x9AEC96U, 0x6337A9U, 0x288468U, 0x369FB3U, 0x774E06U, 0x6C645DU, 0x05B7A9U, 0x4E2E22U,
|
||||
0x551DFFU, 0x1CC78CU, 0x47D611U, 0x4F2DF2U, 0x343E6FU, 0xBF8514U, 0xE655C1U, 0xAD5E5AU, 0xB4EDBFU, 0xDFB4E4U,
|
||||
0xC1265DU, 0x80DD8BU, 0xDBC852U, 0xD25375U, 0x8920ACU, 0xA2BA53U, 0xFB0BC2U, 0x31401DU, 0x28D33CU, 0x63AAE3U,
|
||||
0x18381AU, 0x11238DU, 0x4AD2E4U, 0x434933U, 0x195BABU, 0x56A058U, 0x6FB105U, 0x2C5AAEU, 0x35C97BU, 0xFED9A0U,
|
||||
0xA52295U, 0x8D314EU, 0xD6ECA3U, 0x9F5E30U, 0x84456DU, 0xCFB6DEU, 0xD6AF03U, 0xBD2CE9U, 0xE556FCU, 0xEEC707U,
|
||||
0xB71CD6U, 0x382F59U, 0x43B720U, 0x02E4F7U, 0x195F4EU, 0x51CC99U, 0x0AA550U, 0x013767U, 0x786CBEU, 0x73DD01U,
|
||||
0x2AC6D1U, 0x61159EU, 0x7BA92FU, 0x92BAF4U, 0x896109U, 0xC0521AU, 0x9F9AF7U, 0x942924U, 0xC532B9U, 0xEFE3C2U,
|
||||
0xA6D807U, 0xFD0ABCU, 0xF69369U, 0xAFA033U, 0x44738EU, 0x5D694DU, 0x17C8F0U, 0x0C93A3U, 0x45207AU, 0x1EF9C5U,
|
||||
0x37EB04U, 0x6850FBU, 0x6305EAU, 0x3B9E15U, 0x782DC4U, 0x41774BU, 0x8AF633U, 0xD18DE4U, 0xD81E5DU, 0x83A69AU,
|
||||
0x8AF583U, 0xF06E7CU, 0xBB5FADU, 0xA28416U, 0xE99653U, 0xF06D88U, 0x9FEC35U, 0xC4F7E6U, 0x4C059AU, 0x1F1C19U,
|
||||
0x56EFC4U, 0x4D743FU, 0x24612AU, 0x3F9BD1U, 0x748814U, 0x2C13AFU, 0x27F276U, 0x5EE861U, 0x553B88U, 0x0E0A5FU,
|
||||
0xC791E6U, 0xD8E2B0U, 0x907A69U, 0xABE9C6U, 0xE09217U, 0xB10168U, 0xBA48F9U, 0xE3FA26U, 0x8861CFU, 0x9230D8U,
|
||||
0xDB8B21U, 0xC099B2U, 0x09644FU, 0x52F704U, 0x79AC90U, 0x201F6BU, 0x2E17BEU, 0x77C495U, 0x3CFF48U, 0x172E9BU,
|
||||
0x4E9426U, 0x0D8775U, 0x145E98U, 0x5E6D03U, 0xC5F6D6U, 0xAC242DU, 0xF70D3CU, 0xFEDED2U, 0xA5C543U, 0xAE74BCU,
|
||||
0xD62EE5U, 0x9D9D72U, 0x80029BU, 0xCB534CU, 0x90E175U, 0x19BAAAU, 0x6A3B6BU, 0x6280D4U, 0x39D385U, 0x724B7AU,
|
||||
0x6B78E2U, 0x00A321U, 0x19101CU, 0x5248CFU, 0x0ADB30U, 0x01F0A9U, 0x5A21CEU, 0xB73A17U, 0xACC880U, 0xE55179U,
|
||||
0xFE42A6U, 0xB4B987U, 0xC5AF58U, 0xCE1688U, 0x97C533U, 0x9CCE76U, 0xC73F8DU, 0x8E2510U, 0xB4B6C3U, 0x7D4FFEU,
|
||||
0x665C3DU, 0x2DC7C0U, 0x70B55BU, 0x5B2C2EU, 0x025FF5U, 0x49D470U, 0x53448AU, 0x1A3FD7U, 0x09AC64U, 0x60BDBDU,
|
||||
0x3B467AU, 0xB0D043U, 0xE98B9CU, 0xE33A2DU, 0x9A21E2U, 0xD1C3B3U, 0xCA5A0CU, 0x8709DDU, 0xDCB222U, 0xF5A3AAU,
|
||||
0xBF79DDU, 0xA44A04U, 0xEDD193U, 0x3E006AU, 0x373B21U, 0x4CF994U, 0x47C04FU, 0x1F53DAU, 0x5488A1U, 0x4DB86CU,
|
||||
0x2623DFU, 0x7D7402U, 0x70CF50U, 0x2B9EFDU, 0x232426U, 0xF8A7D3U, 0x91FEC8U, 0x8A4D39U, 0xC117F6U, 0xD0866FU,
|
||||
0x9B3D18U, 0xE36EC1U, 0xE8F576U, 0xB3C5BFU, 0xBA1629U, 0xE1BD50U, 0xA8EC8FU, 0x17763EU, 0x5D45F1U, 0x049CA0U,
|
||||
0x0F8F1FU, 0x5630C6U, 0x7DE225U, 0x26FB38U, 0x6F08CBU, 0x7D0316U, 0x34B28DU, 0x2F68E9U, 0xC47B72U, 0x9DC287U,
|
||||
0x96915CU, 0xCF0B41U, 0x85F8A2U, 0xBAE17FU, 0xF372CCU, 0xE81991U, 0xA1894AU, 0xFAF2EBU, 0xF16134U, 0x89F845U,
|
||||
0x0A8ADBU, 0x53153AU, 0x1806E5U, 0x03FF7CU, 0x6A7C0BU, 0x312692U, 0x399775U, 0x628CACU, 0x6D7FB3U, 0x34EE42U,
|
||||
0x5FF49DU, 0x56073CU, 0x8D1C67U, 0x87CDBBU, 0xDEE708U, 0xB574D5U, 0xA4ADB6U, 0xEF9E2BU, 0xF605D0U, 0xBD7545U,
|
||||
0xE6EE0EU, 0xCE39FBU, 0x950260U, 0xD8929DU, 0x43D9CEU, 0x086A47U, 0x31B3B1U, 0x7AA068U, 0x221ADFU, 0x294B86U,
|
||||
0x72F049U, 0x73E3F8U, 0x083927U, 0x418856U, 0x5AC3C9U, 0x105020U, 0xC969B7U, 0xE2BBEEU, 0xBF2019U, 0xB41181U,
|
||||
0xEFCA6AU, 0xA6FD3FU, 0xBC27A4U, 0xD53651U, 0xCE9D9AU, 0x854EA7U, 0xDC5E74U, 0xDFE5A9U, 0x26B61AU, 0x6C0D57U,
|
||||
0x77DCECU, 0x3EC639U, 0x2575C3U, 0x682CD6U, 0x13AF1DU, 0x1855ECU, 0x404473U, 0x4BDF8AU, 0x12ACDDU, 0xF93754U,
|
||||
0xE207A3U, 0xABD87AU, 0xF04B45U, 0xF03284U, 0xABB05BU, 0x80ABEBU, 0xD95AB4U, 0x92C10DU, 0x8FD2CEU, 0xC42833U,
|
||||
0xEC3920U, 0x37C2FDU, 0x7C5106U, 0x654883U, 0x2EAAF8U, 0x37B12DU, 0x5C20B6U, 0x065B42U, 0x07C909U, 0x5C12B4U,
|
||||
0x152367U, 0x2EB4FAU, 0x65CF19U, 0xFC5F40U, 0xB294FFU, 0xEBA72EU, 0xE03ED1U, 0x9B6CD0U, 0x92D70FU, 0xC944F6U,
|
||||
0x801D60U, 0x9AAE19U, 0xF1F4DEU, 0xA85547U, 0xAB4EB8U, 0x729DE9U, 0x792456U, 0x223697U, 0x4BED0CU, 0x55DE71U,
|
||||
0x1C03A2U, 0x07910FU, 0x4CAADCU, 0x356BA0U, 0x3E5033U, 0x67C3EEU, 0x2D9B05U, 0xB62810U, 0xFFF3EBU, 0xC4E03EU,
|
||||
0x8558A5U, 0xDE0B48U, 0xD5905BU, 0x8D71A2U, 0xA26A75U, 0xFBD8ECU, 0xB08982U, 0xAB1253U, 0xE2A1ECU, 0x79FB3FU,
|
||||
0x116E52U, 0x4A15C9U, 0x43861CU, 0x188FE7U, 0x537DF2U, 0x62E619U, 0x29D7C0U, 0x310C57U, 0x7A1F2EU, 0x25E5B8U,
|
||||
0xAC7451U, 0xC76F86U, 0xDE9C9FU, 0x959460U, 0xCF27B1U, 0xC6FC1EU, 0xBDEDCFU, 0xF416B0U, 0xEF0429U, 0xA49FEEU,
|
||||
0xBDEA17U, 0xFF7104U, 0x06A3F8U, 0x0D8A63U, 0x5219A6U, 0x5B62DDU, 0x00F348U, 0x6969B3U, 0x731A6EU, 0x38816DU,
|
||||
0x61D090U, 0x6A6343U, 0x33F9FEU, 0x18B8A5U, 0xC30340U, 0x8B10DAU, 0x98E80BU, 0xD1FB74U, 0xEA20F5U, 0xA5930AU,
|
||||
0xFC8E93U, 0xF75CC4U, 0xAF673DU, 0xA4E6BAU, 0xDF3D43U, 0x960F9CU, 0x0DD68DU, 0x44E572U, 0x1F7EB2U, 0x35AD09U,
|
||||
0x6C9554U, 0x6746A7U, 0x365D3AU, 0x7DFCF9U, 0x64A6C4U, 0x0B351FU, 0x118CEAU, 0x58DF61U, 0x836434U, 0x8A36CFU,
|
||||
0xF1AB5BU, 0xBA18A0U, 0xA343EDU, 0xE8C27EU, 0xF0F887U, 0xBB2B50U, 0xC03A69U, 0xC9C1A6U, 0x9A5317U, 0x9368C8U,
|
||||
0x5CB919U, 0x26A226U, 0x2F01EFU, 0x74D919U, 0x3DCA80U, 0x2631D7U, 0x6D223EU, 0x54BAA1U, 0x1E4950U, 0x47520BU,
|
||||
0x4CA79EU, 0x97BC75U, 0xBE3EA8U, 0xED479BU, 0xA4D446U, 0xBA4FF5U, 0xF13C39U, 0xE8A46AU, 0x83D7D7U, 0xDA4C0CU,
|
||||
0xD1DDF9U, 0x8AA7F2U, 0xC22427U, 0x793DDCU, 0x30CE45U, 0x2B5522U, 0x6007FBU, 0x39BE6CU, 0x32AD95U, 0x42560BU,
|
||||
0x4D426AU, 0x16D1B5U, 0x5F3A04U, 0x442BDBU, 0x2DF082U, 0xF6C225U, 0xFE59FCU, 0xA5880FU, 0xAEB312U, 0xF761C9U,
|
||||
0x9C582CU, 0x85CBB7U, 0xCE00C3U, 0xD43118U, 0x9DAB9DU, 0xEAF866U, 0xE3437BU, 0x381288U, 0x738955U, 0x6A3BF6U,
|
||||
0x2066ABU, 0x19D570U, 0x52DEC1U, 0x090E1EU, 0x00B5FFU, 0x5BE6E1U, 0x727D38U, 0x284CCFU, 0x639656U, 0xFA8531U,
|
||||
0xBD3CA8U, 0xD4EF77U, 0xCFC586U, 0x841489U, 0x9C0F78U, 0xD7BCA7U, 0x8E671EU, 0xA5774DU, 0xFE8481U, 0xF79F32U,
|
||||
0xAC0AEFU, 0x65F09CU, 0x5FF301U, 0x144ACAU, 0x0D193FU, 0x468224U, 0x13F0D1U, 0x18694AU, 0x63FA87U, 0x2B81F4U,
|
||||
0x30106DU, 0x790A9BU, 0xE2E952U, 0x8970CDU, 0xD003BCU, 0xDB9963U, 0x838AD2U, 0x88731DU, 0xD1E064U, 0xBAFFF3U,
|
||||
0xA10F2AU, 0xEC049DU, 0xBFD7D4U, 0xB7EE2BU, 0x4C7CBBU, 0x478760U, 0x1E9415U, 0x554D9EU, 0x4C7E6BU, 0x07E4B0U,
|
||||
0x3D35ADU, 0x741E4EU, 0x2F8D93U, 0x26FC20U, 0x7D667DU, 0x16B586U, 0x8B8E02U, 0xC91FD9U, 0xD0456CU, 0x9BF237U,
|
||||
0xC0EBCEU, 0xE92849U, 0xB29390U, 0xBBC3E7U, 0xE1787EU, 0xAA6B81U, 0x93B040U, 0xD8005FU, 0x411BAEU, 0x0AC870U,
|
||||
0x51F1D1U, 0x5D328EU, 0x362837U, 0x6799E0U, 0x6C4239U, 0x37711AU, 0x3EABC7U, 0x45BA3CU, 0x0D01A9U, 0x16D6F2U,
|
||||
0xDDCF17U, 0xC46D8CU, 0x8F3670U, 0xF6A723U, 0xFD5CBCU, 0xA74F5DU, 0xEAF582U, 0xF1A43BU, 0x903768U, 0x8B0CC5U,
|
||||
0xC0DC16U, 0x9957CBU, 0x1324F0U, 0x4ABD25U, 0x61AECEU, 0x38545AU, 0x73C701U, 0x68FEF4U, 0x212D6FU, 0x5B3382U,
|
||||
0x52C2D1U, 0x09494CU, 0x065ABFU, 0xDFA126U, 0x9CB149U, 0xA56A98U, 0xEE5927U, 0xF4C0F6U, 0xBD33B8U, 0xE62901U,
|
||||
0xCFB8D6U, 0x94D32FU, 0x9F40B8U, 0xC69AF1U, 0x8CAB0EU, 0x15309FU, 0x7E6360U, 0x21DA31U, 0x2848BAU, 0x733747U,
|
||||
0x72A6D4U, 0x08EDA8U, 0x435F7BU, 0x5A4CD6U, 0x119505U, 0x082658U, 0x433DE3U, 0xB8ED26U, 0xB0D6DDU, 0xEB05C8U,
|
||||
0xA2BC13U, 0xA9BEEAU, 0xD6656DU, 0xDF5614U, 0x848F82U, 0xC41C5BU, 0xDF26A4U, 0x94F7A5U, 0xADCC5AU, 0x665B8BU,
|
||||
0x3F1234U, 0x34A0EDU, 0x6E7BAAU, 0x076813U, 0x1CD1C4U, 0x55833DU, 0x4E1836U, 0x03A9E2U, 0x58F219U, 0x72418CU,
|
||||
0x2B09F7U, 0xA89A72U, 0xF1A1A9U, 0xBA7254U, 0x81EA47U, 0xC899BAU, 0xD20279U, 0x9B13C4U, 0xC0E09FU, 0xCB7E4BU,
|
||||
0xB25FF0U, 0xF98431U, 0xE4974EU, 0x2E6CD7U, 0x35FC00U, 0x5CE7A9U, 0x07147EU, 0x060D07U, 0x5D9F98U, 0x56E449U,
|
||||
0x0E65A6U, 0x659EB7U, 0x7C8D49U, 0x371790U, 0x6C6623U, 0xE5FD6EU, 0x9E6EBDU, 0x921600U, 0xC985D3U, 0x82DAEEU,
|
||||
0x9B7B25U, 0xD0E0F0U, 0xE1924BU, 0xAA091EU, 0xF158F5U, 0xF9E369U, 0x22F1BAU, 0x4B28C7U, 0x509B54U, 0x1B80BDU,
|
||||
0x024162U, 0x497B53U, 0x01A88CU, 0x3E1B5DU, 0x7502F2U, 0x6CD12BU, 0x27EB1CU, 0x7E7AC5U, 0xDDA113U, 0x8596BAU,
|
||||
0xCE5EEDU, 0xD54D14U, 0x9CF68BU, 0x87A54AU, 0xEE1C31U, 0xB58EA4U, 0xBFD55FU, 0xE66482U, 0xE93FA1U, 0x90AD7CU,
|
||||
0x5B04EFU, 0x405713U, 0x09CC48U, 0x13BFEDU, 0x522736U, 0x2914E3U, 0x22CFD8U, 0x7B5E05U, 0x3061E6U, 0x29B37FU,
|
||||
0x43BAA8U, 0x5849D1U, 0x91D25EU, 0xCEE0AFU, 0xC73971U, 0x9C2A40U, 0xB7919FU, 0xEF401EU, 0xA452E1U, 0xB5B9B8U,
|
||||
0xFEA80FU, 0x8533D6U, 0x8C4115U, 0xD7DA28U, 0x5F6BF3U, 0x043006U, 0x4FA39DU, 0x76DBD9U, 0x394C22U, 0x20C7BFU,
|
||||
0x6BB64CU, 0x312C41U, 0x187FB2U, 0x43C46FU, 0x0A55F4U, 0x192E81U, 0xD2BC4AU, 0xCBA5FBU, 0xA15624U, 0xF85DFDU,
|
||||
0xF38ECBU, 0xBA3602U, 0xA125F5U, 0xCEFE6CU, 0x97CF3BU, 0x9D55C2U, 0xC4A64DU, 0x4FBFBCU, 0x1468A3U, 0x7D4352U,
|
||||
0x6ED19DU, 0x270804U, 0x7D3B76U, 0x76A0ABU, 0x0FF018U, 0x0443D5U, 0x5D188EU, 0x16A93BU, 0x0932E0U, 0xC07015U,
|
||||
0xFACB1EU, 0xB39AC3U, 0xE80170U, 0xE3B3ADU, 0xBAEA5EU, 0xD17956U, 0xC042A9U, 0x8A9378U, 0x912DE7U, 0xD86E86U,
|
||||
0x83F559U, 0x2AC4E8U, 0x711F37U, 0x7A0D6EU, 0x26B4C9U, 0x6D6710U, 0x547CE7U, 0x1F8CFEU, 0x449720U, 0x4D3483U,
|
||||
0x16EF5AU, 0x1EFE2DU, 0x6D44B4U, 0xA6174BU, 0xBF8E8AU, 0xF4FD95U, 0xED6764U, 0x86D6BBU, 0xDC8912U, 0xD10A45U,
|
||||
0x8A799CU, 0x83E12AU, 0xF872F3U, 0xB10954U, 0xAA980DU, 0x6083D6U, 0x397163U, 0x3AE8B8U, 0x439BDDU, 0x481046U,
|
||||
0x1302BBU, 0x5AFB68U, 0x50E875U, 0x297396U, 0x26824AU, 0x7D98F1U, 0x344BA4U, 0xAF726FU, 0xE6F5DAU, 0x9C0F01U,
|
||||
0x971C38U, 0xCE85EFU, 0xC5F626U, 0x946D91U, 0xFFBDC8U, 0xE48637U, 0xAC15A6U, 0xB74C48U, 0x7EEE99U, 0x21B586U,
|
||||
0x0A0677U, 0x539FA8U, 0x18CC01U, 0x007652U, 0x4B67CFU, 0x70B43CU, 0x390FF1U, 0x625ECAU, 0x6BD01FU, 0x38E3C4U,
|
||||
0xB23870U, 0xCB893BU, 0x8093C6U, 0x994055U, 0xD679A8U, 0x8DAAFBU, 0xA4B176U, 0xFE018DU, 0xF7CA5CU, 0xACD963U,
|
||||
0xE762B2U, 0xFE323DU, 0x1589C4U, 0x0C5A92U, 0x4F432BU, 0x17F0ECU, 0x1CAA35U, 0x673B82U, 0x6E54DBU, 0x31C724U,
|
||||
0x785CA5U, 0x632C5AU, 0x29B70BU, 0x508490U, 0xDB5D6DU, 0x82CFEEU, 0x89B492U, 0xD22541U, 0xBB2EDCU, 0xA1DD27U,
|
||||
0xE04F62U, 0xFB56D9U, 0xB0A50CU, 0xF9BED7U, 0xC24EFAU, 0x8F5529U, 0x55C6D0U, 0x5E3B47U, 0x07383FU, 0x2CA2F0U,
|
||||
0x75D161U, 0x3E489EU, 0x25BB0FU, 0x6DA170U, 0x7630B1U, 0x174B2EU, 0x4CD8D7U, 0x470180U, 0x9E2339U, 0xD5B8FEU,
|
||||
0xE9EB27U, 0xA2521DU, 0xB941C8U, 0xF0BB23U, 0xAB2AB6U, 0xA271CDU, 0xD9C250U, 0xD3DC83U, 0x8A1D6EU, 0x41A67DU,
|
||||
0x58B580U, 0x3B6C5BU, 0x205ECEU, 0x6985A5U, 0x333471U, 0x3E27CAU, 0x65FD13U, 0x0CCE44U, 0x1747EDU, 0x5C143AU,
|
||||
0x45AF83U, 0x8F7F54U, 0xF6643DU, 0xFDD7A2U, 0xA68E73U, 0xAF3D8CU, 0xF4E79DU, 0xB5E073U, 0x8F59AAU, 0xC40A3DU,
|
||||
0x999044U, 0x922197U, 0xCB7A3AU, 0x60E9E1U, 0x3B90B4U, 0x73020FU, 0x6839DAU, 0x21FA71U, 0x3A632CU, 0x5151DFU,
|
||||
0x088A43U, 0x039B80U, 0x4260FDU, 0x18F36EU, 0x33EB97U, 0xEE1848U, 0xE503C9U, 0xBCA4B6U, 0xF7FC67U, 0xEC6FD8U,
|
||||
0x849C01U, 0x9F8506U, 0xD616FFU, 0x8D6C29U, 0x86FD90U, 0xFF26CFU, 0xF4150EU, 0x2C9EB1U, 0x6FEE60U, 0x74751BU,
|
||||
0x39E696U, 0x429F65U, 0x4B0DB8U, 0x1056ABU, 0x1AE756U, 0x43FC9DU, 0x282F29U, 0x318172U, 0x7A90E7U, 0xE36B1CU,
|
||||
0xA878D9U, 0xF2A0E2U, 0xDB133FU, 0x8008ECU, 0xC1D955U, 0xDAE292U, 0x9570EBU, 0xAC9B74U, 0xE68A85U, 0xBF514BU,
|
||||
0x34635AU, 0x6FFAA5U, 0x66A93CU, 0x1D12CBU, 0x54C382U, 0x4ED915U, 0x056AECU, 0x5C2D37U, 0x779402U, 0x2607C9U,
|
||||
0x2D5D1CU, 0x72ECA6U, 0xBAB7FBU, 0xA12408U, 0xC89C85U, 0xD3CF76U, 0x98542BU, 0xC177B8U, 0xCAAE45U, 0xB29CCEU,
|
||||
0xB9473BU, 0xE2D660U, 0xABEDF1U, 0xA03F1EU, 0x7926C4U, 0x1A95F1U, 0x044E2AU, 0x4D49FFU, 0x56B154U, 0x1FA209U,
|
||||
0x6419FAU, 0x6F4867U, 0x36D394U, 0x3C2199U, 0x653842U, 0x2EABB7U, 0x95C02CU, 0xDC525CU, 0x87CB93U, 0x8EB80AU,
|
||||
0xD423FDU, 0xF152A4U, 0xAAC003U, 0xE15BDAU, 0xF82A0DU, 0xB3B134U, 0xAAB3EBU, 0xC14C0AU, 0x1B5D95U, 0x128664U,
|
||||
0x49357AU, 0x002DA3U, 0x3BDE40U, 0x70C5DDU, 0x6954AEU, 0x23AE73U, 0x76ADE8U, 0x7D760DU, 0x064756U, 0x0FDCE3U,
|
||||
0xD40E38U, 0x9D37F5U, 0x87E4C6U, 0xECDF1AU, 0xB54EA9U, 0xBE1470U, 0xE7B71FU, 0xEC288EU, 0xB77951U, 0xDFC3A0U,
|
||||
0xC490BFU, 0x89095EU, 0x1ABA81U, 0x51E118U, 0x2853EFU, 0x234AB6U, 0x7B8910U, 0x703AC9U, 0x2B6216U, 0x62F127U,
|
||||
0x59CAECU, 0x101B59U, 0x4B2082U, 0xC1F2FFU, 0x88696CU, 0xB358A1U, 0xFA9752U, 0xAD844FU, 0xA63CB4U, 0xFFEF60U,
|
||||
0xF5F4EBU, 0x8C059EU, 0xC71F45U, 0xDCACF0U, 0x95772BU, 0x4E6622U, 0x67CDD5U, 0x3D9F0CU, 0x3406BBU, 0x6F75F2U,
|
||||
0x24EE0DU, 0x3D7E9CU, 0x520542U, 0x4396B3U, 0x09ADBCU, 0x527C45U, 0x5BF292U, 0xA0810BU, 0xE91878U, 0xF20BB5U,
|
||||
0xB9F10EU, 0xA1E0DBU, 0xEA33C0U, 0x938835U, 0x989BFEU, 0xC36342U, 0xCA6011U, 0x95FBECU, 0xFD0A6FU, 0x6E11B2U,
|
||||
0x25C3C1U, 0x3CFA5CU, 0x7769A7U, 0x0EB266U, 0x058079U, 0x5E1988U, 0x167E17U, 0x0DE5EFU, 0x44B428U, 0x7F0E31U,
|
||||
0x349DC6U, 0xEDC41FU, 0xE277A0U, 0xBA6DE1U, 0x99BE1EU, 0xC2178FU, 0x8B4450U, 0x90FF39U, 0xD9EFAAU, 0x823457U,
|
||||
0xA88785U, 0xF1DE98U, 0xFA4D73U, 0x3377E6U, 0x68A41DU, 0x43AD48U, 0x1A1AD3U, 0x14C836U, 0x4DF1EDU, 0x0622D0U,
|
||||
0x173903U, 0x7C88FEU, 0x27527DU, 0x2E41A5U, 0xF4FADAU, 0xFDBB4BU, 0x8601A4U, 0xCDD235U, 0xD4CB6AU, 0x9F7893U,
|
||||
0x862304U, 0xCCB3EDU, 0xB388BAU, 0xBA5B23U, 0xE1C0DCU, 0xE8A00DU, 0x3B3F27U, 0x500CF2U, 0x48D509U, 0x034694U,
|
||||
0x5A3CC7U, 0x51AD6AU, 0x0AB6B9U, 0x234544U, 0x785E57U, 0x30DE9AU, 0x2B2561U, 0x6036F4U, 0xDDCF8FU, 0x96DD5BU,
|
||||
0xCF46D0U, 0xCCB729U, 0x96A4FEU, 0xDF3FC7U, 0xE44D10U, 0xADC4F9U, 0xB61366U, 0xFD2837U, 0xA4B888U, 0x8EC359U,
|
||||
0x5750B6U, 0x5C49AFU, 0x07BA79U, 0x4A2080U, 0x517307U, 0x38DA7EU, 0x62C9ADU, 0x611230U, 0x38A2CBU, 0x33F98EU,
|
||||
0x4A4A35U, 0x0153E0U, 0x98815BU, 0xD23A06U, 0xD929C5U, 0x80E079U, 0xEBD7AAU, 0xF20D57U, 0xBD1C4CU, 0xE6A78DU,
|
||||
0xEF7472U, 0x954CE3U, 0x9CDF9CU, 0xCF8455U, 0x0437C2U, 0x1DFE3BU, 0x56EC6CU, 0x6F57D5U, 0x25061BU, 0x7E95AAU,
|
||||
0x772FF5U, 0x2C7C24U, 0x05C59BU, 0x5A965AU, 0x111D21U, 0x892DBCU, 0xC2F26FU, 0x9B6192U, 0xB81891U, 0xE38B6EU,
|
||||
0xEA91B6U, 0xB16221U, 0xF9FB48U, 0xC2C8DFU, 0x890226U, 0x9013F9U, 0xDBE848U, 0x02FB07U, 0x0D62D6U, 0x77906DU,
|
||||
0x3E8BB0U, 0x2538C3U, 0x6C614EU, 0x77F39CU, 0x141861U, 0x4D0D7AU, 0x47968FU, 0x1EE544U, 0x157DD1U, 0xCEEEAAU,
|
||||
0xA7953FU, 0xBC06D4U, 0xF57E09U, 0xABED3AU, 0xA2EEE3U, 0xD91734U, 0xD2849CU, 0x8BDEC3U, 0xC06F32U, 0xD174ADU,
|
||||
0x9BA77CU, 0x201C93U, 0x690C8AU, 0x22F77DU, 0x3BF4E4U, 0x702933U, 0x4B9B5AU, 0x0380C1U, 0x585134U, 0x556AEEU,
|
||||
0x0EF9CBU, 0x45A310U, 0x7C12CDU, 0xB7C97EU, 0xAFEA23U, 0xEC72C0U, 0xB7215DU, 0x9E9A8EU, 0xC50BF3U, 0xCC5068U,
|
||||
0x97E28DU, 0xDDB916U, 0xC42846U, 0xAF93B9U, 0xF2D020U, 0x796CC7U, 0x223F9EU, 0x2BA429U, 0x5095F0U, 0x18473FU,
|
||||
0x03DC8EU, 0x40EFD1U, 0x593620U, 0x1225BFU, 0x6BCF76U, 0x605E40U, 0xBA6599U, 0xF3B66AU, 0xE8AEF7U, 0x851DBCU,
|
||||
0x9EC649U, 0xD5D5D2U, 0x8C2C27U, 0x863E7CU, 0xDFB5D9U, 0xF4C002U, 0xA55BDFU, 0xEEE9ECU, 0x75B020U, 0x3C23D3U,
|
||||
0x06584AU, 0x4FCB15U, 0x1453A4U, 0x1F306BU, 0x42AB9AU, 0x09FA05U, 0x30415CU, 0x7A53ABU, 0x61AA22U, 0x2839D5U,
|
||||
0xF3228CU, 0xDAD032U, 0x89C9E3U, 0x820A2CU, 0xCAB91DU, 0x91A4C6U, 0x985673U, 0xE34DB8U, 0xA8DCE5U, 0xB52756U,
|
||||
0xFE358BU, 0xE6EE78U, 0x0DDF75U, 0x5654AFU, 0x5F075AU, 0x04BFC1U, 0x0D2CB4U, 0x56577FU, 0x34C6C2U, 0x2D9D11U,
|
||||
0x662F48U, 0x3FB4FFU, 0x34E536U, 0x4F4E89U, 0xC61C58U, 0x988107U, 0xD132A7U, 0xCA6978U, 0x81D881U, 0xB8C296U,
|
||||
0xF3114FU, 0xAA2AA8U, 0xA0FB31U, 0xF37142U, 0xDA429FU, 0x819B24U, 0x4888E1U, 0x5333FAU, 0x1AE30FU, 0x40D0D5U,
|
||||
0x6F0B68U, 0x36182BU, 0x3DA0F6U, 0x646345U, 0x2F7898U, 0x14CDF3U, 0x5C9666U, 0xC704BDU, 0x8E7F4CU, 0xDDEED3U,
|
||||
0xD655BAU, 0xAF062DU, 0xE49EF5U, 0xFDFD02U, 0xB7661BU, 0xA8F7F4U, 0xC18D25U, 0x9A1E9AU, 0x9305CBU, 0x48F414U,
|
||||
0x43EFB5U, 0x1B1D6AU, 0x708413U, 0x698780U, 0x2A7C4DU, 0x6168BFU, 0x78F3A2U, 0x130059U, 0x0B1BCCU, 0x40CA07U,
|
||||
0x1FF072U, 0x9663E9U, 0xCD9A14U, 0xE499C7U, 0xBF0AEAU, 0xF57239U, 0xECE1E4U, 0xA7BA5FU, 0xDE098FU, 0xD591E0U,
|
||||
0x86E271U, 0x8F79AEU, 0xD52817U, 0x1C8350U, 0x2711A9U, 0x684C3EU, 0x71FFE7U, 0x3AE490U, 0x633619U, 0x498FE6U,
|
||||
0x10DC37U, 0x1B670DU, 0x4066D8U, 0x09BC13U, 0x328FAEU, 0xFB16FDU, 0xA9C500U, 0xA2FF93U, 0xFB2C5EU, 0xF03565U,
|
||||
0x8D86B0U, 0xC65D4BU, 0xDD7DCEU, 0x95E615U, 0x8EB169U, 0xE708FAU, 0xBCDB03U, 0x37C1C4U, 0x6E72FDU, 0x25232AU,
|
||||
0x3DB8F3U, 0x5ECA4CU, 0x45430DU, 0x0CF0B2U, 0x57AB61U, 0x5E3ABCU, 0x210087U, 0x2BD343U, 0xF248B8U, 0xB9392DU,
|
||||
0xA0A376U, 0xEBB09FU, 0x905908U, 0x99CAF1U, 0xD3F5A6U, 0xCA251FU, 0x813ED0U, 0xF2CD01U, 0xFBD63EU, 0xA046EEU,
|
||||
0x29BD51U, 0x76AE98U, 0x3C274FU, 0x055476U, 0x4ECEA5U, 0x573F58U, 0x1C24DBU, 0x47B786U, 0x6ECC7DU, 0x345CE8U,
|
||||
0x7D0703U, 0x66B456U, 0xAF3DECU, 0xBC6F31U, 0xD7D0A2U, 0x8EC1CFU, 0x80321CU, 0xD9A9A1U, 0xD2FB7AU, 0xA9422BU,
|
||||
0xE05184U, 0xFB8A55U, 0xB22AAAU, 0xE831B3U, 0x63E264U, 0x1ADB8CU, 0x11081BU, 0x4832E2U, 0x0BA1BDU, 0x10781CU,
|
||||
0x784BC3U, 0x679052U, 0x2E902DU, 0x752BFCU, 0x7EFC57U, 0x27C58AU, 0xCC57D9U, 0xD40C64U, 0x9FBFB6U, 0x84665BU,
|
||||
0xCD7540U, 0xB6CF95U, 0xBF8E6EU, 0xE415FBU, 0xE62690U, 0xBFFE0DU, 0xF04DFEU, 0xC91623U, 0x028520U, 0x19BCD9U,
|
||||
0x506E06U, 0x0AEDB6U, 0x23D4E9U, 0x780728U, 0x331997U, 0x3AE84EU, 0x6173B9U, 0x6840A0U, 0x129B67U, 0x598B9EU,
|
||||
0xC87009U, 0x877370U, 0x9EEAEBU, 0xF5190EU, 0xAC03D4U, 0xA690C1U, 0xFDE93AU, 0xB47AF7U, 0xAF8044U, 0xC69119U,
|
||||
0xDD0ACAU, 0x166977U, 0x4EF0BCU, 0x45E2C9U, 0x3C1D52U, 0x3F8E87U, 0x64D73CU, 0x296574U, 0x327E83U, 0x7A8F1AU,
|
||||
0x0114EDU, 0x0A1734U, 0x53EF3BU, 0xD8FCCAU, 0x812715U, 0xEA94A4U, 0xF185EBU, 0xB95F3AU, 0xA26C85U, 0xEBB55CU,
|
||||
0xB0862AU, 0x930CA3U, 0xCEDD70U, 0x85E6CDU, 0x9D7196U, 0x562A63U, 0x6D9AE8U, 0x24411DU, 0x7F5246U, 0x76EBDBU,
|
||||
0x2DB928U, 0x2712E5U, 0x5E83D7U, 0x15D80AU, 0x0C6BD1U, 0x473170U, 0x54A02FU, 0xB99B9EU, 0xE34841U, 0xEAD090U,
|
||||
0xB1E33FU, 0xFA2866U, 0xE31991U, 0x88C208U, 0x8154FFU, 0xDB6FB7U, 0x92BE28U, 0x89A5D9U, 0xE25606U, 0x7BCE37U,
|
||||
0x30FDFCU, 0x693E21U, 0x6F2792U, 0x3495CFU, 0x5DCE6CU, 0x465DB1U, 0x0FA46AU, 0x14B75FU, 0x5F2D85U, 0x275C60U,
|
||||
0x2CC7FBU, 0xF56486U, 0xFE3C55U, 0xA5ABC8U, 0xECD02BU, 0xD743F2U, 0x9FDAC5U, 0xC0A81CU, 0xC33383U, 0x9A2262U,
|
||||
0xB1D93DU, 0xE8DA8DU, 0x232252U, 0x39B19BU, 0x70AAACU, 0x6B5975U, 0x024182U, 0x59921BU, 0x522974U, 0x0B38A5U,
|
||||
0x01F33EU, 0x78C1CBU, 0x3758D0U, 0x242F3DU, 0xEDB4EFU, 0xB66672U, 0xBF5701U, 0xC5CCDCU, 0xCE9F77U, 0x9726A2U,
|
||||
0xDCA4F9U, 0xC5FF4CU, 0xAE4E87U, 0xB51576U, 0xFDA7E9U, 0xA63C90U, 0x2F6D47U, 0x74D6CFU, 0x1BC538U, 0x0A1D21U,
|
||||
0x413EDEU, 0x58E50FU, 0x127480U, 0x6B4BF1U, 0x60992EU, 0x2BA297U, 0x327340U, 0x79E809U, 0xA0DABAU, 0x8A0367U,
|
||||
0xD1009DU, 0x98BB98U, 0x836A63U, 0xCE70F6U, 0xF5832DU, 0xB69850U, 0xEE29D3U, 0xE5732EU, 0xBCE0FDU, 0xB75962U,
|
||||
0x4C1A13U, 0x0589DCU, 0x1EF165U, 0x5666B7U, 0x4DFDEAU, 0x268E59U, 0x7F1794U, 0x74256FU, 0x29FE7AU, 0x626F81U,
|
||||
0x700404U, 0x1996DFU, 0x828FA2U, 0xCB7C31U, 0x9067CCU, 0x9B940EU, 0xE20C17U, 0xE81FE8U, 0xB1E439U, 0xFAF586U,
|
||||
0xE17FC7U, 0xA88C18U, 0xD397A1U, 0x5E4276U, 0x04794FU, 0x0FEB88U, 0x5E9271U, 0x3501E6U, 0x2C9A3EU, 0x67EA51U,
|
||||
0x7C61C0U, 0x34323BU, 0x6F89EEU, 0x4618F5U, 0x1D4218U, 0xD4F1CBU, 0xCFE876U, 0x841B25U, 0xB888F8U, 0xF3D053U,
|
||||
0xAA7386U, 0xA168BCU, 0xF2BB69U, 0xFB8792U, 0x80541FU, 0xC8CF4CU, 0xC3FEB5U, 0x182522U, 0x1117CBU, 0x6A9E9CU,
|
||||
0x234D05U, 0x3876FAU, 0x72A42BU, 0x2FBD84U, 0x240ED4U, 0x5DD54BU, 0x56C4B2U, 0x057E65U, 0x4C2D4CU, 0xD7849BU,
|
||||
0xBFD762U, 0xA44DF9U, 0xEFFEACU, 0xB6A347U, 0xBD30D2U, 0xC40B29U, 0x8FDB74U, 0x9540E6U, 0xDC330BU, 0xC3BAD8U,
|
||||
0x8A89E5U, 0x71533EU, 0x7AC0BBU, 0x2BB140U, 0x212A11U, 0x7838AEU, 0x13C17FU, 0x08D290U, 0x414989U, 0x1AA85EU,
|
||||
0x13B2A6U, 0x494131U, 0x625AD8U, 0xBBCF87U, 0xF43516U, 0xED26E9U, 0xA6BF78U, 0x9FCC17U, 0xDD57CEU, 0x86B75DU,
|
||||
0x8FACA0U, 0xD43FE3U, 0x9D445EU, 0xA6D584U, 0x6DCF71U, 0x753C6AU, 0x3EA5AFU, 0x67F654U, 0x4C4CC9U, 0x134DBAU,
|
||||
0x1AB667U, 0x4125E4U, 0x097E19U, 0x12CA0AU, 0x71D1F3U, 0x78022CU, 0xA33BACU, 0xEAA953U, 0xF17A02U, 0x9B53BDU,
|
||||
0xC28074U, 0xC9BB83U, 0x90299AU, 0x9BF04DU, 0xC4C3B4U, 0xAD583BU, 0xB7084AU, 0xFEB3D1U, 0x656004U, 0x2E69FEU,
|
||||
0x5FDAF3U, 0x548000U, 0x0D37DDU, 0x472E4EU, 0x5CFD33U, 0x1546F8U, 0x2E164DU, 0x678D96U, 0x3CBEE3U, 0x337768U,
|
||||
0xEBE5BDU, 0xC09E47U, 0x990D5EU, 0xD234A9U, 0xC9E720U, 0x887DF7U, 0xD34C0EU, 0xFB9711U, 0xA084E0U, 0xA96C2FU,
|
||||
0xF27FBEU, 0xB9E4C1U, 0x001318U, 0x4B02AFU, 0x56B867U, 0x1CEB30U, 0x477289U, 0x4E8152U, 0x358AF7U, 0x3C1AACU,
|
||||
0x676159U, 0x24F2C2U, 0x3C6917U, 0x57197CU, 0x8E82E1U, 0x85F112U, 0xDE68CFU, 0xD77BDDU, 0x8C9130U, 0xE400EBU,
|
||||
0xFB5B5EU, 0xB0E885U, 0xA9F6D4U, 0xE2277BU, 0x9B9CA2U, 0x108F15U, 0x5A764CU, 0x0B64ABU, 0x00AF32U, 0x599CEDU,
|
||||
0x72059DU, 0x29D702U, 0x60ECE3U, 0x7A7D3CU, 0x330625U, 0x0C95D6U, 0x474D0BU, 0x9E7EA8U, 0x95FDF5U, 0xCCA666U,
|
||||
0x86179BU, 0xBD8D40U, 0xFCDA65U, 0xE763BFU, 0xAE304AU, 0xF58AD1U, 0xDE9B9CU, 0x86406FU, 0x8DE3F2U, 0x54B801U,
|
||||
0x1B28D8U, 0x0213D7U, 0x69C026U, 0x7259B9U, 0x3A6B48U, 0x61B017U, 0x68819FU, 0x135A68U, 0x50D9B1U, 0x49E386U,
|
||||
0x02325FU, 0x9A29B0U, 0xD19E23U, 0xAAC77EU, 0xA3558DU, 0xFCAE04U, 0xF5BFF3U, 0xAE04AAU, 0xC44635U, 0xDDDDC5U,
|
||||
0x966C4AU, 0xCF373BU, 0xC4A4E4U, 0x1FD47DU, 0x3E4F8AU, 0x64DC43U, 0x2DA574U, 0x3637ADU, 0x7D5C56U, 0x44CFC3U,
|
||||
0x0BD688U, 0x52257DU, 0x59BBE7U, 0x03AA1AU, 0x4A5119U, 0xF142C4U, 0xB89A37U, 0xB329AAU, 0xE822D1U, 0xA9D114U,
|
||||
0x93C88FU, 0xDA5A7AU, 0xC1A121U, 0x8AB090U, 0xD36B5EU, 0xDC58A7U, 0xA5C0B0U, 0x2F8369U, 0x74389EU, 0x3DAB17U,
|
||||
0x26D368U, 0x4F40F9U, 0x141F26U, 0x1DAEC7U, 0x473558U, 0x446721U, 0x1DDEF6U, 0x769D6EU, 0xEF0E8DU, 0xA434D0U,
|
||||
0xBFE56BU, 0xF35EBEU, 0x884D45U, 0x819440U, 0xDAA69BU, 0x917D26U, 0x88ECF5U, 0xC3C788U, 0xFB150BU, 0xB02ED6U,
|
||||
0x63BF24U, 0x6A6439U, 0x3153D2U, 0x188B03U, 0x43989CU, 0x0923EDU, 0x147232U, 0x5FF99BU, 0x060B4CU, 0x2D10B5U,
|
||||
0x76A1A2U, 0x7FFA7BU, 0xA568D4U, 0xECD104U, 0xD7827BU, 0x9C19EAU, 0x8D6831U, 0xC6E2DCU, 0x9F71CFU, 0x950A32U,
|
||||
0xEE9BE1U, 0xA3A16CU, 0xB8761FU, 0xF16FC2U, 0x6A9C79U, 0x010FACU, 0x491786U, 0x52F453U, 0x1BEF88U, 0x007C35U,
|
||||
0x4B8566U, 0x32978FU, 0x316C18U, 0x697DC1U, 0x62E6BEU, 0x3B142FU, 0xD40DC0U, 0xCFCE11U, 0x86F58EU, 0xDD66F6U,
|
||||
0xD53E31U, 0x8E8988U, 0xA5125FU, 0xFC6366U, 0xB7F9B9U, 0xAEAA78U, 0xE513C3U, 0xD69096U, 0x1ECB6DU, 0x4579F8U,
|
||||
0x4C6033U, 0x13B34EU, 0x5888DCU, 0x615821U, 0x2AE3F2U, 0x32F0FFU, 0x792B04U, 0x220A91U, 0x0B906AU, 0xD0432BU,
|
||||
0xD97294U, 0x82AD4DU, 0xC8BE9AU, 0xD90623U, 0xB2D564U, 0xEBEE9CU, 0xE02D03U, 0xBF35D2U, 0xB686ADU, 0xCCDD2CU,
|
||||
0x854CD3U, 0x1EF70AU, 0x55A51DU, 0x4C1CE4U, 0x074F67U, 0x7ED49AU, 0x7476C9U, 0x2F2F75U, 0x26BCBEU, 0x75876BU,
|
||||
0x1C5650U, 0x07C885U, 0x48BB7EU, 0x9022F3U, 0x9B11A0U, 0xC2CA5DU, 0xE9C8CEU, 0xA07133U, 0xFBA238U, 0xF0B9E9U,
|
||||
0xA84917U, 0x835286U, 0xDAC179U, 0x913830U, 0x822B87U, 0x4BD95EU, 0x30D289U, 0x3C43A0U, 0x67B87FU, 0x6CAA8EU,
|
||||
0x353311U, 0x7E4440U, 0x47DFABU, 0x0C8E3FU, 0x1634C4U, 0x5FA7D9U, 0x04CC0AU, 0xAD5DE7U, 0xF64774U, 0xBDB409U,
|
||||
0xAC2DD2U, 0xE67E67U, 0xFBC5ACU, 0x90D5F9U, 0xCB0E42U, 0xC23D9FU, 0x99B67DU, 0x9047E4U, 0xEA5DB3U, 0x218E0AU,
|
||||
0x38B7D5U, 0x732034U, 0x6AFA2BU, 0x21CBFAU, 0x5A1005U, 0x5B039CU, 0x01A8FBU, 0x4C7822U, 0x574395U, 0x3CD04DU,
|
||||
0xA5811AU, 0xEE3BB3U, 0xB76868U, 0xBDF19DU, 0xE64286U, 0xCF1943U, 0x949BF8U, 0xDDA225U, 0xC67156U, 0x8FCACBU,
|
||||
0xF59B08U, 0xF605F5U, 0x2B36EFU, 0x20EF1AU, 0x797CC1U, 0x324664U, 0x1985BFU, 0x419CE4U, 0x4A6F51U, 0x13748AU,
|
||||
0x58C42FU, 0x631F74U, 0x2A0CA1U, 0x71F51AU, 0xF9E7D7U, 0xA27CA5U, 0xA99F38U, 0xD886EBU, 0x973516U, 0x8E6F1DU,
|
||||
0xC5FEECU, 0xDF0133U, 0xB61282U, 0xED8ADDU, 0xE4F954U, 0xBF7AA3U, 0x74617AU, 0x6D904DU, 0x070A95U, 0x1E795AU,
|
||||
0x55E0EBU, 0x0EF334U, 0x0F0845U, 0x7098CAU, 0x798313U, 0x2360E0U, 0x687BFDU, 0x71AB0EU, 0xBA10C3U, 0x830370U,
|
||||
0xC8FA2DU, 0x93EDB7U, 0x9B3742U, 0xC00689U, 0xA99DBCU, 0xB25E67U, 0xF964BAU, 0xE0F509U, 0xA7AE44U, 0xFF1DB7U,
|
||||
0x54C42EU, 0x0DF6F1U, 0x066D90U, 0x5D3C0EU, 0x1487FFU, 0x2F8460U, 0x675E19U, 0x3CEFDEU, 0x37B447U, 0x6E27B0U,
|
||||
0x651369U, 0x9CC856U, 0xD77B97U, 0xC9604CU, 0x88B1F9U, 0x939BA2U, 0xFA4856U, 0xB1D1DDU, 0xAAE200U, 0xE33873U,
|
||||
0xB829EEU, 0xB0D20DU, 0xCBC190U, 0x407AEBU, 0x19AA3EU, 0x52A1A5U, 0x4B1240U, 0x204B1BU, 0x3ED9A2U, 0x7F2274U,
|
||||
0x2437ADU, 0x2DAC8AU, 0x76DF53U, 0x5D45ACU, 0x04F43DU, 0xCEBFE2U, 0xD72CC3U, 0x9C551CU, 0xE7C7E5U, 0xEEDC72U,
|
||||
0xB52D1BU, 0xBCB6CCU, 0xE6A454U, 0xA95FA7U, 0x904EFAU, 0xD3A551U, 0xCA3684U, 0x01265FU, 0x5ADD6AU, 0x72CEB1U,
|
||||
0x29135CU, 0x60A1CFU, 0x7BBA92U, 0x304921U, 0x2950FCU, 0x42D316U, 0x1AA903U, 0x1138F8U, 0x48E329U, 0xC7D0A6U,
|
||||
0xBC48DFU, 0xFD1B08U, 0xE6A0B1U, 0xAE3366U, 0xF55AAFU, 0xFEC898U, 0x879341U, 0x8C22FEU, 0xD5392EU, 0x9EEA61U,
|
||||
0x8456D0U, 0x6D450BU, 0x769EF6U, 0x3FADE5U, 0x606508U, 0x6BD6DBU, 0x3ACD46U, 0x101C3DU, 0x5927F8U, 0x02F543U,
|
||||
0x096C96U, 0x505FCCU, 0xBB8C71U, 0xA296B2U, 0xE8370FU, 0xF36C5CU, 0xBADF85U, 0xE1063AU, 0xC814FBU, 0x97AF04U,
|
||||
0x9CFA15U, 0xC461EAU, 0x87D23BU, 0xBE88B4U, 0x7509CCU, 0x2E721BU, 0x27E1A2U, 0x7C5965U, 0x750A7CU, 0x0F9183U,
|
||||
0x44A052U, 0x5D7BE9U, 0x1669ACU, 0x0F9277U, 0x6013CAU, 0x3B0819U, 0xB3FA65U, 0xE0E3E6U, 0xA9103BU, 0xB28BC0U,
|
||||
0xDB9ED5U, 0xC0642EU, 0x8B77EBU, 0xD3EC50U, 0xD80D89U, 0xA1179EU, 0xAAC477U, 0xF1F5A0U, 0x386E19U, 0x271D4FU,
|
||||
0x6F8596U, 0x541639U, 0x1F6DE8U, 0x4EFE97U, 0x45B706U, 0x1C05D9U, 0x779E30U, 0x6DCF27U, 0x2474DEU, 0x3F664DU,
|
||||
0xF69BB0U, 0xAD08FBU, 0x86536FU, 0xDFE094U, 0xD1E841U, 0x883B6AU, 0xC300B7U, 0xE8D164U, 0xB16BD9U, 0xF2788AU,
|
||||
0xEBA167U, 0xA192FCU, 0x3A0929U, 0x53DBD2U, 0x08F2C3U, 0x01212DU, 0x5A3ABCU, 0x518B43U, 0x29D11AU, 0x62628DU,
|
||||
0x7FFD64U, 0x34ACB3U, 0x6F1E8AU, 0xE64555U, 0x95C494U, 0x9D7F2BU, 0xC62C7AU, 0x8DB485U, 0x94871DU, 0xFF5CDEU,
|
||||
0xE6EFE3U, 0xADB730U, 0xF524CFU, 0xFE0F56U, 0xA5DE31U, 0x48C5E8U, 0x53377FU, 0x1AAE86U, 0x01BD59U, 0x4B4678U,
|
||||
0x3A50A7U, 0x31E977U, 0x683ACCU, 0x633189U, 0x38C072U, 0x71DAEFU, 0x4B493CU, 0x82B001U, 0x99A3C2U, 0xD2383FU,
|
||||
0x8F4AA4U, 0xA4D3D1U, 0xFDA00AU, 0xB62B8FU, 0xACBB75U, 0xE5C028U, 0xF6539BU, 0x9F4242U, 0xC4B985U, 0x4F2FBCU,
|
||||
0x167463U, 0x1CC5D2U, 0x65DE1DU, 0x2E3C4CU, 0x35A5F3U, 0x78F622U, 0x234DDDU, 0x0A5C55U, 0x408622U, 0x5BB5FBU,
|
||||
0x122E6CU, 0xC1FF95U, 0xC8C4DEU, 0xB3066BU, 0xB83FB0U, 0xE0AC25U, 0xAB775EU, 0xB24793U, 0xD9DC20U, 0x828BFDU,
|
||||
0x8F30AFU, 0xD46102U, 0xDCDBD9U, 0x07582CU, 0x6E0137U, 0x75B2C6U, 0x3EE809U, 0x2F7990U, 0x64C2E7U, 0x1C913EU,
|
||||
0x170A89U, 0x4C3A40U, 0x45E9D6U, 0x1E42AFU, 0x571370U, 0xE889C1U, 0xA2BA0EU, 0xFB635FU, 0xF070E0U, 0xA9CF39U,
|
||||
0x821DDAU, 0xD904C7U, 0x90F734U, 0x82FCE9U, 0xCB4D72U, 0xD09716U, 0x3B848DU, 0x623D78U, 0x696EA3U, 0x30F4BEU,
|
||||
0x7A075DU, 0x451E80U, 0x0C8D33U, 0x17E66EU, 0x5E76B5U, 0x050D14U, 0x0E9ECBU, 0x7607BAU, 0xF57524U, 0xACEAC5U,
|
||||
0xE7F91AU, 0xFC0083U, 0x9583F4U, 0xCED96DU, 0xC6688AU, 0x9D7353U, 0x92804CU, 0xCB11BDU, 0xA00B62U, 0xA9F8C3U,
|
||||
0x72E398U, 0x783244U, 0x2118F7U, 0x4A8B2AU, 0x5B5249U, 0x1061D4U, 0x09FA2FU, 0x428ABAU, 0x1911F1U, 0x31C604U,
|
||||
0x6AFD9FU, 0x276D62U, 0xBC2631U, 0xF795B8U, 0xCE4C4EU, 0x855F97U, 0xDDE520U, 0xD6B479U, 0x8D0FB6U, 0x8C1C07U,
|
||||
0xF7C6D8U, 0xBE77A9U, 0xA53C36U, 0xEFAFDFU, 0x369648U, 0x1D4411U, 0x40DFE6U, 0x4BEE7EU, 0x103595U, 0x5902C0U,
|
||||
0x43D85BU, 0x2AC9AEU, 0x316265U, 0x7AB158U, 0x23A18BU, 0x201A56U, 0xD949E5U, 0x93F2A8U, 0x882313U, 0xC139C6U,
|
||||
0xDA8A3CU, 0x97D329U, 0xEC50E2U, 0xE7AA13U, 0xBFBB8CU, 0xB42075U, 0xED5322U, 0x06C8ABU, 0x1DF85CU, 0x542785U,
|
||||
0x0FB4BAU, 0x0FCD7BU, 0x544FA4U, 0x7F5414U, 0x26A54BU, 0x6D3EF2U, 0x702D31U, 0x3BD7CCU, 0x13C6DFU, 0xC83D02U,
|
||||
0x83AEF9U, 0x9AB77CU, 0xD15507U, 0xC84ED2U, 0xA3DF49U, 0xF9A4BDU, 0xF836F6U, 0xA3ED4BU, 0xEADC98U, 0xD14B05U,
|
||||
0x9A30E6U, 0x03A0BFU, 0x4D6B00U, 0x1458D1U, 0x1FC12EU, 0x64932FU, 0x6D28F0U, 0x36BB09U, 0x7FE29FU, 0x6551E6U,
|
||||
0x0E0B21U, 0x57AAB8U, 0x54B147U, 0x8D6216U, 0x86DBA9U, 0xDDC968U, 0xB412F3U, 0xAA218EU, 0xE3FC5DU, 0xF86EF0U,
|
||||
0xB35523U, 0xCA945FU, 0xC1AFCCU, 0x983C11U, 0xD264FAU, 0x49D7EFU, 0x000C14U, 0x3B1FC1U, 0x7AA75AU, 0x21F4B7U,
|
||||
0x2A6FA4U, 0x728E5DU, 0x5D958AU, 0x042713U, 0x4F767DU, 0x54EDACU, 0x1D5E13U, 0x8604C0U, 0xEE91ADU, 0xB5EA36U,
|
||||
0xBC79E3U, 0xE77018U, 0xAC820DU, 0x9D19E6U, 0xD6283FU, 0xCEF3A8U, 0x85E0D1U, 0xDA1A47U, 0x538BAEU, 0x389079U,
|
||||
0x216360U, 0x6A6B9FU, 0x30D84EU, 0x3903E1U, 0x421230U, 0x0BE94FU, 0x10FBD6U, 0x5B6011U, 0x4215E8U, 0x008EFBU,
|
||||
0xF95C07U, 0xF2759CU, 0xADE659U, 0xA49D22U, 0xFF0CB7U, 0x96964CU, 0x8CE591U, 0xC77E92U, 0x9E2F6FU, 0x959CBCU,
|
||||
0xCC0601U, 0xE7475AU, 0x3CFCBFU, 0x74EF25U, 0x6717F4U, 0x2E048BU, 0x15DF0AU, 0x5A6CF5U, 0x03716CU, 0x08A33BU,
|
||||
0x5098C2U, 0x5B1945U, 0x20C2BCU, 0x69F063U, 0xF22972U, 0xBB1A8DU, 0xE0814DU, 0xCA52F6U, 0x936AABU, 0x98B958U,
|
||||
0xC9A2C5U, 0x820306U, 0x9B593BU, 0xF4CAE0U, 0xEE7315U, 0xA7209EU, 0x7C9BCBU, 0x75C930U, 0x0E54A4U, 0x45E75FU,
|
||||
0x5CBC12U, 0x173D81U, 0x0F0778U, 0x44D4AFU, 0x3FC596U, 0x363E59U, 0x65ACE8U, 0x6C9737U, 0xA346E6U, 0xD95DD9U,
|
||||
0xD0FE10U, 0x8B26E6U, 0xC2357FU, 0xD9CE28U, 0x92DDC1U, 0xAB455EU, 0xE1B6AFU, 0xB8ADF4U, 0xB35861U, 0x68438AU,
|
||||
0x41C157U, 0x12B864U, 0x5B2BB9U, 0x45B00AU, 0x0EC3C6U, 0x175B95U, 0x7C2828U, 0x25B3F3U, 0x2E2206U, 0x75580DU,
|
||||
0x3DDBD8U, 0x86C223U, 0xCF31BAU, 0xD4AADDU, 0x9FF804U, 0xC64193U, 0xCD526AU, 0xBDA9F4U, 0xB2BD95U, 0xE92E4AU,
|
||||
0xA0C5FBU, 0xBBD424U, 0xD20F7DU, 0x093DDAU, 0x01A603U, 0x5A77F0U, 0x514CEDU, 0x089E36U, 0x63A7D3U, 0x7A3448U,
|
||||
0x31FF3CU, 0x2BCEE7U, 0x625462U, 0x150799U, 0x1CBC84U, 0xC7ED77U, 0x8C76AAU, 0x95C409U, 0xDF9954U, 0xE62A8FU,
|
||||
0xAD213EU, 0xF6F1E1U, 0xFF4A00U, 0xA4191EU, 0x8D82C7U, 0xD7B330U, 0x9C69A9U, 0x057ACEU, 0x42C357U, 0x2B1088U,
|
||||
0x303A79U, 0x7BEB76U, 0x63F087U, 0x284358U, 0x7198E1U, 0x5A88B2U, 0x017B7EU, 0x0860CDU, 0x53F510U, 0x9A0F63U,
|
||||
0xA00CFEU, 0xEBB535U, 0xF2E6C0U, 0xB97DDBU, 0xEC0F2EU, 0xE796B5U, 0x9C0578U, 0xD47E0BU, 0xCFEF92U, 0x86F564U,
|
||||
0x1D16ADU, 0x768F32U, 0x2FFC43U, 0x24669CU, 0x7C752DU, 0x778CE2U, 0x2E1F9BU, 0x45000CU, 0x5EF0D5U, 0x13FB62U,
|
||||
0x40282BU, 0x4811D4U, 0xB38344U, 0xB8789FU, 0xE16BEAU, 0xAAB261U, 0xB38194U, 0xF81B4FU, 0xC2CA52U, 0x8BE1B1U,
|
||||
0xD0726CU, 0xD903DFU, 0x829982U, 0xE94A79U, 0x7471FDU, 0x36E026U, 0x2FBA93U, 0x640DC8U, 0x3F1431U, 0x16D7B6U,
|
||||
0x4D6C6FU, 0x443C18U, 0x1E8781U, 0x55947EU, 0x6C4FBFU, 0x27FFA0U, 0xBEE451U, 0xF5378FU, 0xAE0E2EU, 0xA2CD71U,
|
||||
0xC9D7C8U, 0x98661FU, 0x93BDC6U, 0xC88EE5U, 0xC15438U, 0xBA45C3U, 0xF2FE56U, 0xE9290DU, 0x2230E8U, 0x3B9273U,
|
||||
0x70C98FU, 0x0958DCU, 0x02A343U, 0x58B0A2U, 0x150A7DU, 0x0E5BC4U, 0x6FC897U, 0x74F33AU, 0x3F23E9U, 0x66A834U,
|
||||
0xECDB0FU, 0xB542DAU, 0x9E5131U, 0xC7ABA5U, 0x8C38FEU, 0x97010BU, 0xDED290U, 0xA4CC7DU, 0xAD3D2EU, 0xF6B6B3U,
|
||||
0xF9A540U, 0x205ED9U, 0x634EB6U, 0x5A9567U, 0x11A6D8U, 0x0B3F09U };
|
||||
|
||||
const unsigned int A_TABLE[] = { 0U, 4U, 8U, 12U, 16U, 20U, 24U, 28U, 32U, 36U, 40U, 44U,
|
||||
48U, 52U, 56U, 60U, 64U, 68U, 1U, 5U, 9U, 13U, 17U, 21U };
|
||||
const unsigned int B_TABLE[] = { 25U, 29U, 33U, 37U, 41U, 45U, 49U, 53U, 57U, 61U, 65U, 69U,
|
||||
2U, 6U, 10U, 14U, 18U, 22U, 26U, 30U, 34U, 38U, 42U };
|
||||
const unsigned int C_TABLE[] = { 46U, 50U, 54U, 58U, 62U, 66U, 70U, 3U, 7U, 11U, 15U, 19U,
|
||||
23U, 27U, 31U, 35U, 39U, 43U, 47U, 51U, 55U, 59U, 63U, 67U, 71U };
|
||||
|
||||
const unsigned char AMBE_SILENCE[] = {0xB9U, 0xE8U, 0x81U, 0x52U, 0x61U, 0x73U, 0x00U, 0x2AU, 0x6BU};
|
||||
|
||||
CModeConv::CModeConv() :
|
||||
m_m17N(0U),
|
||||
m_dmrN(0U),
|
||||
m_M17(5000U, "DMR2M17"),
|
||||
m_DMR(5000U, "M172DMR"),
|
||||
m_m17GainMultiplier(1),
|
||||
m_m17Attenuate(false)
|
||||
{
|
||||
m_mbe = new MBEVocoder();
|
||||
m_c2 = new CCodec2(true);
|
||||
}
|
||||
|
||||
CModeConv::~CModeConv()
|
||||
{
|
||||
}
|
||||
|
||||
void CModeConv::setM17GainAdjDb(std::string dbstring)
|
||||
{
|
||||
float db = std::stof(dbstring);
|
||||
|
||||
float ratio = powf(10.0, (db/10.0));
|
||||
if(db < 0){
|
||||
ratio = 1/ratio;
|
||||
m_m17Attenuate = true;
|
||||
}
|
||||
m_m17GainMultiplier = (uint16_t)roundf(ratio);
|
||||
}
|
||||
|
||||
void CModeConv::putDMRHeader()
|
||||
{
|
||||
const uint8_t quiet[] = { 0x00u, 0x01u, 0x43u, 0x09u, 0xe4u, 0x9cu, 0x08u, 0x21u };
|
||||
|
||||
m_M17.addData(&TAG_HEADER, 1U);
|
||||
m_M17.addData(quiet, 8U);
|
||||
m_m17N += 1U;
|
||||
}
|
||||
|
||||
void CModeConv::putDMREOT()
|
||||
{
|
||||
const uint8_t quiet[] = { 0x00u, 0x01u, 0x43u, 0x09u, 0xe4u, 0x9cu, 0x08u, 0x21u };
|
||||
|
||||
m_M17.addData(&TAG_EOT, 1U);
|
||||
m_M17.addData(quiet, 8U);
|
||||
m_m17N += 1U;
|
||||
}
|
||||
|
||||
void CModeConv::putDMR(unsigned char* data)
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
int16_t audio[160U];
|
||||
uint8_t ambe[9U];
|
||||
uint8_t v_ambe[9U];
|
||||
uint8_t codec2[8U];
|
||||
|
||||
::memset(audio, 0, sizeof(audio));
|
||||
::memset(ambe, 0, sizeof(ambe));
|
||||
::memset(v_ambe, 0, sizeof(v_ambe));
|
||||
::memset(codec2, 0, sizeof(codec2));
|
||||
|
||||
decode(data, ambe, 0U);
|
||||
m_mbe->decode_2450(audio, ambe);
|
||||
m_c2->codec2_encode(codec2, audio);
|
||||
m_M17.addData(&TAG_DATA, 1U);
|
||||
m_M17.addData(codec2, 8U);
|
||||
m_m17N += 1U;
|
||||
|
||||
data += 9U;
|
||||
for (unsigned int i = 0U; i < 4U; i++)
|
||||
v_ambe[i] = data[i];
|
||||
|
||||
v_ambe[4U] = data[4U] & 0xF0;
|
||||
v_ambe[4U] |= data[10U] & 0x0F;
|
||||
|
||||
for (unsigned int i = 0U; i < 4U; i++)
|
||||
v_ambe[i + 5U] = data[i + 11U];
|
||||
|
||||
decode(v_ambe, ambe, 0U);
|
||||
m_mbe->decode_2450(audio, ambe);
|
||||
m_c2->codec2_encode(codec2, audio);
|
||||
m_M17.addData(&TAG_DATA, 1U);
|
||||
m_M17.addData(codec2, 8U);
|
||||
m_m17N += 1U;
|
||||
|
||||
data += 15U;;
|
||||
decode(data, ambe, 0U);
|
||||
m_mbe->decode_2450(audio, ambe);
|
||||
m_c2->codec2_encode(codec2, audio);
|
||||
m_M17.addData(&TAG_DATA, 1U);
|
||||
m_M17.addData(codec2, 8U);
|
||||
m_m17N += 1U;
|
||||
}
|
||||
|
||||
void CModeConv::putM17Header()
|
||||
{
|
||||
unsigned char vch[9U];
|
||||
|
||||
::memset(vch, 0, 9U);
|
||||
|
||||
m_DMR.addData(&TAG_HEADER, 1U);
|
||||
m_DMR.addData(vch, 9U);
|
||||
m_dmrN += 1U;
|
||||
}
|
||||
|
||||
void CModeConv::putM17EOT()
|
||||
{
|
||||
unsigned char vch[9U];
|
||||
|
||||
::memset(vch, 0, 9U);
|
||||
|
||||
unsigned int fill = 3U - (m_dmrN % 3U);
|
||||
for (unsigned int i = 0U; i < fill; i++) {
|
||||
m_DMR.addData(&TAG_DATA, 1U);
|
||||
m_DMR.addData(AMBE_SILENCE, 9U);
|
||||
m_dmrN += 1U;
|
||||
}
|
||||
|
||||
m_DMR.addData(&TAG_EOT, 1U);
|
||||
m_DMR.addData(vch, 9U);
|
||||
m_dmrN += 1U;
|
||||
}
|
||||
|
||||
void CModeConv::putM17(unsigned char* data)
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
int16_t audio[160U];
|
||||
int16_t audio_adjusted[160U];
|
||||
uint8_t ambe[9U];
|
||||
uint8_t codec2[8U];
|
||||
uint8_t vch[10U];
|
||||
::memset(audio, 0, sizeof(audio));
|
||||
::memset(ambe, 0, sizeof(ambe));
|
||||
|
||||
::memcpy(codec2, &data[36], 8);
|
||||
m_c2->codec2_decode(audio, codec2);
|
||||
for(int i = 0; i < 160; ++i){
|
||||
m_m17Attenuate ? audio_adjusted[i] = audio[i] / m_m17GainMultiplier : audio[i] * m_m17GainMultiplier;
|
||||
}
|
||||
m_mbe->encode_2450(audio_adjusted, ambe);
|
||||
|
||||
encode(ambe, vch, 0U);
|
||||
m_DMR.addData(&TAG_DATA, 1U);
|
||||
m_DMR.addData(vch, 9U);
|
||||
m_dmrN += 1U;
|
||||
|
||||
::memcpy(codec2, &data[44], 8);
|
||||
m_c2->codec2_decode(audio, codec2);
|
||||
for(int i = 0; i < 160; ++i){
|
||||
m_m17Attenuate ? audio_adjusted[i] = audio[i] / m_m17GainMultiplier : audio[i] * m_m17GainMultiplier;
|
||||
}
|
||||
m_mbe->encode_2450(audio_adjusted, ambe);
|
||||
|
||||
encode(ambe, vch, 0U);
|
||||
m_DMR.addData(&TAG_DATA, 1U);
|
||||
m_DMR.addData(vch, 9U);
|
||||
m_dmrN += 1U;
|
||||
}
|
||||
|
||||
unsigned int CModeConv::getDMR(unsigned char* data)
|
||||
{
|
||||
unsigned char tmp[9U];
|
||||
unsigned char tag[1U];
|
||||
|
||||
tag[0U] = TAG_NODATA;
|
||||
|
||||
if (m_dmrN >= 1U) {
|
||||
m_DMR.peek(tag, 1U);
|
||||
//LogMessage("CModeConv::getDMR %d:%d:%d", m_DMR.isEmpty(), m_dmrN, tag[0]);
|
||||
if (tag[0U] != TAG_DATA) {
|
||||
m_DMR.getData(tag, 1U);
|
||||
m_DMR.getData(data, 9U);
|
||||
m_dmrN -= 1U;
|
||||
if(tag[0U] == TAG_EOT){
|
||||
m_DMR.clear();
|
||||
m_dmrN = 0;
|
||||
}
|
||||
return tag[0U];
|
||||
}
|
||||
}
|
||||
|
||||
if (m_dmrN >= 3U) {
|
||||
m_DMR.getData(tag, 1U);
|
||||
m_DMR.getData(data, 9U);
|
||||
m_dmrN -= 1U;
|
||||
|
||||
m_DMR.getData(tag, 1U);
|
||||
m_DMR.getData(tmp, 9U);
|
||||
m_dmrN -= 1U;
|
||||
|
||||
::memcpy(data + 9U, tmp, 4U);
|
||||
data[13U] = tmp[4U] & 0xF0U;
|
||||
data[19U] = tmp[4U] & 0x0FU;
|
||||
::memcpy(data + 20U, tmp + 5U, 4U);
|
||||
|
||||
m_DMR.getData(tag, 1U);
|
||||
m_DMR.getData(data + 24U, 9U);
|
||||
m_dmrN -= 1U;
|
||||
|
||||
return TAG_DATA;
|
||||
}
|
||||
else
|
||||
return TAG_NODATA;
|
||||
}
|
||||
|
||||
unsigned int CModeConv::getM17(unsigned char* data)
|
||||
{
|
||||
unsigned char tag[2U];
|
||||
|
||||
tag[0U] = TAG_NODATA;
|
||||
tag[1U] = TAG_NODATA;
|
||||
|
||||
if (m_m17N >= 2U) {
|
||||
m_M17.getData(tag, 1U);
|
||||
m_M17.getData(data, 8U);
|
||||
m_M17.getData(tag+1, 1U);
|
||||
m_M17.getData(data+8, 8U);
|
||||
fprintf(stderr, "getM17() m_m17N:tag1:tag2 == %d:%d:%d\n", m_m17N, tag[0U], tag[1U]);
|
||||
m_m17N -= 2U;
|
||||
}
|
||||
return (tag[1U] == TAG_EOT) ? tag[1U] : tag[0];
|
||||
}
|
||||
|
||||
void CModeConv::decode(const unsigned char* in, unsigned char* out, unsigned int offset) const
|
||||
{
|
||||
assert(in != NULL);
|
||||
assert(out != NULL);
|
||||
|
||||
unsigned int a = 0U;
|
||||
unsigned int MASK = 0x800000U;
|
||||
for (unsigned int i = 0U; i < 24U; i++, MASK >>= 1) {
|
||||
unsigned int aPos = A_TABLE[i];
|
||||
if (READ_BIT(in, aPos))
|
||||
a |= MASK;
|
||||
}
|
||||
|
||||
unsigned int b = 0U;
|
||||
MASK = 0x400000U;
|
||||
for (unsigned int i = 0U; i < 23U; i++, MASK >>= 1) {
|
||||
unsigned int bPos = B_TABLE[i];
|
||||
if (READ_BIT(in, bPos))
|
||||
b |= MASK;
|
||||
}
|
||||
|
||||
unsigned int c = 0U;
|
||||
MASK = 0x1000000U;
|
||||
for (unsigned int i = 0U; i < 25U; i++, MASK >>= 1) {
|
||||
unsigned int cPos = C_TABLE[i];
|
||||
if (READ_BIT(in, cPos))
|
||||
c |= MASK;
|
||||
}
|
||||
|
||||
a >>= 12;
|
||||
|
||||
// The PRNG
|
||||
b ^= (PRNG_TABLE[a] >> 1);
|
||||
b >>= 11;
|
||||
|
||||
MASK = 0x000800U;
|
||||
for (unsigned int i = 0U; i < 12U; i++, MASK >>= 1) {
|
||||
unsigned int aPos = i + offset + 0U;
|
||||
unsigned int bPos = i + offset + 12U;
|
||||
WRITE_BIT(out, aPos, a & MASK);
|
||||
WRITE_BIT(out, bPos, b & MASK);
|
||||
}
|
||||
|
||||
MASK = 0x1000000U;
|
||||
for (unsigned int i = 0U; i < 25U; i++, MASK >>= 1) {
|
||||
unsigned int cPos = i + offset + 24U;
|
||||
WRITE_BIT(out, cPos, c & MASK);
|
||||
}
|
||||
}
|
||||
|
||||
void CModeConv::encode(const unsigned char* in, unsigned char* out, unsigned int offset) const
|
||||
{
|
||||
assert(in != NULL);
|
||||
assert(out != NULL);
|
||||
|
||||
unsigned int aOrig = 0U;
|
||||
unsigned int bOrig = 0U;
|
||||
unsigned int cOrig = 0U;
|
||||
|
||||
unsigned int MASK = 0x000800U;
|
||||
for (unsigned int i = 0U; i < 12U; i++, MASK >>= 1) {
|
||||
unsigned int n1 = i + offset + 0U;
|
||||
unsigned int n2 = i + offset + 12U;
|
||||
if (READ_BIT(in, n1))
|
||||
aOrig |= MASK;
|
||||
if (READ_BIT(in, n2))
|
||||
bOrig |= MASK;
|
||||
}
|
||||
|
||||
MASK = 0x1000000U;
|
||||
for (unsigned int i = 0U; i < 25U; i++, MASK >>= 1) {
|
||||
unsigned int n = i + offset + 24U;
|
||||
if (READ_BIT(in, n))
|
||||
cOrig |= MASK;
|
||||
}
|
||||
|
||||
unsigned int a = CGolay24128::encode24128(aOrig);
|
||||
|
||||
// The PRNG
|
||||
unsigned int p = PRNG_TABLE[aOrig] >> 1;
|
||||
|
||||
unsigned int b = CGolay24128::encode23127(bOrig) >> 1;
|
||||
b ^= p;
|
||||
|
||||
MASK = 0x800000U;
|
||||
for (unsigned int i = 0U; i < 24U; i++, MASK >>= 1) {
|
||||
unsigned int aPos = A_TABLE[i];
|
||||
WRITE_BIT(out, aPos, a & MASK);
|
||||
}
|
||||
|
||||
MASK = 0x400000U;
|
||||
for (unsigned int i = 0U; i < 23U; i++, MASK >>= 1) {
|
||||
unsigned int bPos = B_TABLE[i];
|
||||
WRITE_BIT(out, bPos, b & MASK);
|
||||
}
|
||||
|
||||
MASK = 0x1000000U;
|
||||
for (unsigned int i = 0U; i < 25U; i++, MASK >>= 1) {
|
||||
unsigned int cPos = C_TABLE[i];
|
||||
WRITE_BIT(out, cPos, cOrig & MASK);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (C) 2010,2014,2016,2018 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||
* Copyright (C) 2020 by Doug McLain AD8DP
|
||||
*
|
||||
* 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 "Defines.h"
|
||||
#include "RingBuffer.h"
|
||||
#include "MBEVocoder.h"
|
||||
#include "codec2/codec2.h"
|
||||
|
||||
#if !defined(MODECONV_H)
|
||||
#define MODECONV_H
|
||||
|
||||
class CModeConv {
|
||||
public:
|
||||
CModeConv();
|
||||
~CModeConv();
|
||||
|
||||
void setM17GainAdjDb(std::string dbstring);
|
||||
void putDMR(unsigned char* data);
|
||||
void putDMRHeader();
|
||||
void putDMREOT();
|
||||
|
||||
void putM17(unsigned char* data);
|
||||
void putM17Header();
|
||||
void putM17EOT();
|
||||
|
||||
unsigned int getM17(unsigned char* data);
|
||||
unsigned int getDMR(unsigned char* data);
|
||||
|
||||
private:
|
||||
unsigned int m_m17N;
|
||||
unsigned int m_dmrN;
|
||||
CRingBuffer<unsigned char> m_M17;
|
||||
CRingBuffer<unsigned char> m_DMR;
|
||||
MBEVocoder *m_mbe;
|
||||
CCodec2 *m_c2;
|
||||
uint16_t m_m17GainMultiplier;
|
||||
bool m_m17Attenuate;
|
||||
void encode(const unsigned char* in, unsigned char* out, unsigned int offset) const;
|
||||
void decode(const unsigned char* in, unsigned char* out, unsigned int offset) const;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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 "Mutex.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
|
||||
CMutex::CMutex() :
|
||||
m_handle()
|
||||
{
|
||||
m_handle = ::CreateMutex(NULL, FALSE, NULL);
|
||||
}
|
||||
|
||||
CMutex::~CMutex()
|
||||
{
|
||||
::CloseHandle(m_handle);
|
||||
}
|
||||
|
||||
void CMutex::lock()
|
||||
{
|
||||
::WaitForSingleObject(m_handle, INFINITE);
|
||||
}
|
||||
|
||||
void CMutex::unlock()
|
||||
{
|
||||
::ReleaseMutex(m_handle);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
CMutex::CMutex() :
|
||||
m_mutex(PTHREAD_MUTEX_INITIALIZER)
|
||||
{
|
||||
}
|
||||
|
||||
CMutex::~CMutex()
|
||||
{
|
||||
}
|
||||
|
||||
void CMutex::lock()
|
||||
{
|
||||
::pthread_mutex_lock(&m_mutex);
|
||||
}
|
||||
|
||||
void CMutex::unlock()
|
||||
{
|
||||
::pthread_mutex_unlock(&m_mutex);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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(MUTEX_H)
|
||||
#define MUTEX_H
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
class CMutex
|
||||
{
|
||||
public:
|
||||
CMutex();
|
||||
~CMutex();
|
||||
|
||||
void lock();
|
||||
void unlock();
|
||||
|
||||
private:
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
HANDLE m_handle;
|
||||
#else
|
||||
pthread_mutex_t m_mutex;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* 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 "QR1676.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
const unsigned int ENCODING_TABLE_1676[] =
|
||||
{0x0000U, 0x0273U, 0x04E5U, 0x0696U, 0x09C9U, 0x0BBAU, 0x0D2CU, 0x0F5FU, 0x11E2U, 0x1391U, 0x1507U, 0x1774U,
|
||||
0x182BU, 0x1A58U, 0x1CCEU, 0x1EBDU, 0x21B7U, 0x23C4U, 0x2552U, 0x2721U, 0x287EU, 0x2A0DU, 0x2C9BU, 0x2EE8U,
|
||||
0x3055U, 0x3226U, 0x34B0U, 0x36C3U, 0x399CU, 0x3BEFU, 0x3D79U, 0x3F0AU, 0x411EU, 0x436DU, 0x45FBU, 0x4788U,
|
||||
0x48D7U, 0x4AA4U, 0x4C32U, 0x4E41U, 0x50FCU, 0x528FU, 0x5419U, 0x566AU, 0x5935U, 0x5B46U, 0x5DD0U, 0x5FA3U,
|
||||
0x60A9U, 0x62DAU, 0x644CU, 0x663FU, 0x6960U, 0x6B13U, 0x6D85U, 0x6FF6U, 0x714BU, 0x7338U, 0x75AEU, 0x77DDU,
|
||||
0x7882U, 0x7AF1U, 0x7C67U, 0x7E14U, 0x804FU, 0x823CU, 0x84AAU, 0x86D9U, 0x8986U, 0x8BF5U, 0x8D63U, 0x8F10U,
|
||||
0x91ADU, 0x93DEU, 0x9548U, 0x973BU, 0x9864U, 0x9A17U, 0x9C81U, 0x9EF2U, 0xA1F8U, 0xA38BU, 0xA51DU, 0xA76EU,
|
||||
0xA831U, 0xAA42U, 0xACD4U, 0xAEA7U, 0xB01AU, 0xB269U, 0xB4FFU, 0xB68CU, 0xB9D3U, 0xBBA0U, 0xBD36U, 0xBF45U,
|
||||
0xC151U, 0xC322U, 0xC5B4U, 0xC7C7U, 0xC898U, 0xCAEBU, 0xCC7DU, 0xCE0EU, 0xD0B3U, 0xD2C0U, 0xD456U, 0xD625U,
|
||||
0xD97AU, 0xDB09U, 0xDD9FU, 0xDFECU, 0xE0E6U, 0xE295U, 0xE403U, 0xE670U, 0xE92FU, 0xEB5CU, 0xEDCAU, 0xEFB9U,
|
||||
0xF104U, 0xF377U, 0xF5E1U, 0xF792U, 0xF8CDU, 0xFABEU, 0xFC28U, 0xFE5BU};
|
||||
|
||||
const unsigned int DECODING_TABLE_1576[] =
|
||||
{0x0000U, 0x0001U, 0x0002U, 0x0003U, 0x0004U, 0x0005U, 0x0006U, 0x4020U, 0x0008U, 0x0009U, 0x000AU, 0x000BU,
|
||||
0x000CU, 0x000DU, 0x2081U, 0x2080U, 0x0010U, 0x0011U, 0x0012U, 0x0013U, 0x0014U, 0x0C00U, 0x0016U, 0x0C02U,
|
||||
0x0018U, 0x0120U, 0x001AU, 0x0122U, 0x4102U, 0x0124U, 0x4100U, 0x4101U, 0x0020U, 0x0021U, 0x0022U, 0x4004U,
|
||||
0x0024U, 0x4002U, 0x4001U, 0x4000U, 0x0028U, 0x0110U, 0x1800U, 0x1801U, 0x002CU, 0x400AU, 0x4009U, 0x4008U,
|
||||
0x0030U, 0x0108U, 0x0240U, 0x0241U, 0x0034U, 0x4012U, 0x4011U, 0x4010U, 0x0101U, 0x0100U, 0x0103U, 0x0102U,
|
||||
0x0105U, 0x0104U, 0x1401U, 0x1400U, 0x0040U, 0x0041U, 0x0042U, 0x0043U, 0x0044U, 0x0045U, 0x0046U, 0x4060U,
|
||||
0x0048U, 0x0049U, 0x0301U, 0x0300U, 0x004CU, 0x1600U, 0x0305U, 0x0304U, 0x0050U, 0x0051U, 0x0220U, 0x0221U,
|
||||
0x3000U, 0x4200U, 0x3002U, 0x4202U, 0x0058U, 0x1082U, 0x1081U, 0x1080U, 0x3008U, 0x4208U, 0x2820U, 0x1084U,
|
||||
0x0060U, 0x0061U, 0x0210U, 0x0211U, 0x0480U, 0x0481U, 0x4041U, 0x4040U, 0x0068U, 0x2402U, 0x2401U, 0x2400U,
|
||||
0x0488U, 0x3100U, 0x2810U, 0x2404U, 0x0202U, 0x0880U, 0x0200U, 0x0201U, 0x0206U, 0x0884U, 0x0204U, 0x0205U,
|
||||
0x0141U, 0x0140U, 0x0208U, 0x0209U, 0x2802U, 0x0144U, 0x2800U, 0x2801U, 0x0080U, 0x0081U, 0x0082U, 0x0A00U,
|
||||
0x0084U, 0x0085U, 0x2009U, 0x2008U, 0x0088U, 0x0089U, 0x2005U, 0x2004U, 0x2003U, 0x2002U, 0x2001U, 0x2000U,
|
||||
0x0090U, 0x0091U, 0x0092U, 0x1048U, 0x0602U, 0x0C80U, 0x0600U, 0x0601U, 0x0098U, 0x1042U, 0x1041U, 0x1040U,
|
||||
0x2013U, 0x2012U, 0x2011U, 0x2010U, 0x00A0U, 0x00A1U, 0x00A2U, 0x4084U, 0x0440U, 0x0441U, 0x4081U, 0x4080U,
|
||||
0x6000U, 0x1200U, 0x6002U, 0x1202U, 0x6004U, 0x2022U, 0x2021U, 0x2020U, 0x0841U, 0x0840U, 0x2104U, 0x0842U,
|
||||
0x2102U, 0x0844U, 0x2100U, 0x2101U, 0x0181U, 0x0180U, 0x0B00U, 0x0182U, 0x5040U, 0x0184U, 0x2108U, 0x2030U,
|
||||
0x00C0U, 0x00C1U, 0x4401U, 0x4400U, 0x0420U, 0x0421U, 0x0422U, 0x4404U, 0x0900U, 0x0901U, 0x1011U, 0x1010U,
|
||||
0x0904U, 0x2042U, 0x2041U, 0x2040U, 0x0821U, 0x0820U, 0x1009U, 0x1008U, 0x4802U, 0x0824U, 0x4800U, 0x4801U,
|
||||
0x1003U, 0x1002U, 0x1001U, 0x1000U, 0x0501U, 0x0500U, 0x1005U, 0x1004U, 0x0404U, 0x0810U, 0x1100U, 0x1101U,
|
||||
0x0400U, 0x0401U, 0x0402U, 0x0403U, 0x040CU, 0x0818U, 0x1108U, 0x1030U, 0x0408U, 0x0409U, 0x040AU, 0x2060U,
|
||||
0x0801U, 0x0800U, 0x0280U, 0x0802U, 0x0410U, 0x0804U, 0x0412U, 0x0806U, 0x0809U, 0x0808U, 0x1021U, 0x1020U,
|
||||
0x5000U, 0x2200U, 0x5002U, 0x2202U};
|
||||
|
||||
#define X14 0x00004000 /* vector representation of X^{14} */
|
||||
#define X8 0x00000100 /* vector representation of X^{8} */
|
||||
#define MASK7 0xffffff00 /* auxiliary vector for testing */
|
||||
#define GENPOL 0x00000139 /* generator polinomial, g(x) */
|
||||
|
||||
unsigned int CQR1676::getSyndrome1576(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 = X14;
|
||||
|
||||
if (pattern >= X8) {
|
||||
while (pattern & MASK7) {
|
||||
while (!(aux & pattern))
|
||||
aux = aux >> 1;
|
||||
|
||||
pattern ^= (aux / X8) * GENPOL;
|
||||
}
|
||||
}
|
||||
|
||||
return pattern;
|
||||
}
|
||||
|
||||
// Compute the EMB against a precomputed list of correct words
|
||||
void CQR1676::encode(unsigned char* data)
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
unsigned int value = (data[0U] >> 1) & 0x7FU;
|
||||
unsigned int cksum = ENCODING_TABLE_1676[value];
|
||||
|
||||
data[0U] = cksum >> 8;
|
||||
data[1U] = cksum & 0xFFU;
|
||||
}
|
||||
|
||||
unsigned char CQR1676::decode(const unsigned char* data)
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
unsigned int code = (data[0U] << 7) + (data[1U] >> 1);
|
||||
unsigned int syndrome = getSyndrome1576(code);
|
||||
unsigned int error_pattern = DECODING_TABLE_1576[syndrome];
|
||||
|
||||
code ^= error_pattern;
|
||||
|
||||
return code >> 7;
|
||||
}
|
|
@ -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 QR1676_H
|
||||
#define QR1676_H
|
||||
|
||||
class CQR1676 {
|
||||
public:
|
||||
static void encode(unsigned char* data);
|
||||
|
||||
static unsigned char decode(const unsigned char* data);
|
||||
|
||||
private:
|
||||
static unsigned int getSyndrome1576(unsigned int pattern);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,54 @@
|
|||
# Description
|
||||
|
||||
This is the source code of P252DMR, a software for digital voice conversion from P25 to DMR digital mode, based on Jonathan G4KLX's [MMDVM](https://github.com/g4klx) software. Unlike the other cross mode utilities upon which this is based, this utility performs software transcoding between IMBE 4400x2800(P25) and AMBE+2 2450x1150(DMR).
|
||||
|
||||
You can use this software with MMDVMHost and P25Gateway, with the default UDP ports:
|
||||
|
||||
MMDVMHost(P25 Mode):32010 <-> 42020:P25Gateway:42010 <-> 42012:P252DMR <-> (DMR Master server)
|
||||
|
||||
If you want to connect directly to a XLX reflector (with DMR support), you only need to uncomment ([DMR Network] section):
|
||||
|
||||
XLXFile=XLXHosts.txt
|
||||
XLXReflector=950
|
||||
XLXModule=D
|
||||
|
||||
and replace XLXReflector and XLXModule according your preferences. Also, you need to configure the DMR port according the XLX reflector port, for example:
|
||||
|
||||
Port=62030
|
||||
|
||||
StartupDstId, StartupPC and Address parameters don't care in XLX mode.
|
||||
|
||||
This software is licenced under the GPL v2 and is intended for amateur and educational use only. Use of this software for commercial purposes is strictly forbidden.
|
||||
|
||||
# Building
|
||||
|
||||
This utility is not built with the other cross mode ulitities, and has 2 external dependencies:
|
||||
|
||||
imbe_vocoder https://github.com/nostar/imbe_vocoder
|
||||
md380_vocoder https://github.com/nostar/md380_vocoder
|
||||
|
||||
With these dependencies installed, run 'make' from the source directory.
|
||||
|
||||
# Crosslink configuration
|
||||
|
||||
You can use P252DMR to link a [P25 Reflector](https://github.com/g4klx/P25Clients) to a DMR network (without using any RF link):
|
||||
|
||||
P25Reflector <-> P252DMR <-> any DMR Network
|
||||
|
||||
Install the P252DMR software at the same server where P25Reflector is located. Configure your [DMR Network] section (P252DMR.ini) as usual, depending on your preferred DMR network. Then, you only need to match the P25Reflector UDP port (Port in [Network], P25Reflector.ini) to P25 UDP port (DstPort in [P25 Network], P252DMR.ini).
|
||||
|
||||
For example, a common UDP port in P25Reflector.ini:
|
||||
|
||||
[Network]
|
||||
Port=41000
|
||||
|
||||
Then you need to configure P252DMR.ini (example):
|
||||
|
||||
[P25 Network]
|
||||
Callsign=CE1ABC
|
||||
TG=10300
|
||||
DstAddress=127.0.0.1
|
||||
DstPort=41000
|
||||
LocalAddress=127.0.0.1
|
||||
LocalPort=41015
|
||||
Daemon=0
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* 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 <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
const unsigned int NPAR = 3U;
|
||||
|
||||
/* 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];
|
||||
}
|
||||
|
|
@ -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
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright (C) 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 "Reflectors.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <cctype>
|
||||
|
||||
CReflectors::CReflectors(const std::string& hostsFile, unsigned int reloadTime) :
|
||||
m_hostsFile(hostsFile),
|
||||
m_reflectors(),
|
||||
m_timer(1000U, reloadTime * 60U)
|
||||
{
|
||||
if (reloadTime > 0U)
|
||||
m_timer.start();
|
||||
}
|
||||
|
||||
CReflectors::~CReflectors()
|
||||
{
|
||||
for (std::vector<CReflector*>::iterator it = m_reflectors.begin(); it != m_reflectors.end(); ++it)
|
||||
delete *it;
|
||||
|
||||
m_reflectors.clear();
|
||||
}
|
||||
|
||||
bool CReflectors::load()
|
||||
{
|
||||
for (std::vector<CReflector*>::iterator it = m_reflectors.begin(); it != m_reflectors.end(); ++it)
|
||||
delete *it;
|
||||
|
||||
m_reflectors.clear();
|
||||
|
||||
FILE* fp = ::fopen(m_hostsFile.c_str(), "rt");
|
||||
if (fp != NULL) {
|
||||
char buffer[100U];
|
||||
while (::fgets(buffer, 100U, fp) != NULL) {
|
||||
if (buffer[0U] == '#')
|
||||
continue;
|
||||
|
||||
char* p1 = ::strtok(buffer, ";\r\n");
|
||||
char* p2 = ::strtok(NULL, ";\r\n");
|
||||
char* p3 = ::strtok(NULL, "\r\n");
|
||||
|
||||
if (p1 != NULL && p2 != NULL && p3 != NULL) {
|
||||
CReflector* refl = new CReflector;
|
||||
refl->m_id = (unsigned int)::atoi(p1);
|
||||
refl->m_address = std::string(p2);
|
||||
refl->m_startup = (unsigned int)::atoi(p3);
|
||||
m_reflectors.push_back(refl);
|
||||
}
|
||||
}
|
||||
|
||||
::fclose(fp);
|
||||
}
|
||||
|
||||
size_t size = m_reflectors.size();
|
||||
LogInfo("Loaded %u XLX reflectors", size);
|
||||
|
||||
size = m_reflectors.size();
|
||||
if (size == 0U)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CReflector* CReflectors::find(unsigned int id)
|
||||
{
|
||||
for (std::vector<CReflector*>::iterator it = m_reflectors.begin(); it != m_reflectors.end(); ++it) {
|
||||
if (id == (*it)->m_id)
|
||||
return *it;
|
||||
}
|
||||
|
||||
LogMessage("Trying to find non existent XLX reflector with an id of %u", id);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CReflectors::clock(unsigned int ms)
|
||||
{
|
||||
m_timer.clock(ms);
|
||||
|
||||
if (m_timer.isRunning() && m_timer.hasExpired()) {
|
||||
load();
|
||||
m_timer.start();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (C) 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.
|
||||
*/
|
||||
|
||||
#if !defined(Reflectors_H)
|
||||
#define Reflectors_H
|
||||
|
||||
#include "Timer.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class CReflector {
|
||||
public:
|
||||
CReflector() :
|
||||
m_id(0U),
|
||||
m_address(),
|
||||
m_startup(0U)
|
||||
{
|
||||
}
|
||||
|
||||
unsigned int m_id;
|
||||
std::string m_address;
|
||||
unsigned int m_startup;
|
||||
};
|
||||
|
||||
class CReflectors {
|
||||
public:
|
||||
CReflectors(const std::string& hostsFile, unsigned int reloadTime);
|
||||
~CReflectors();
|
||||
|
||||
bool load();
|
||||
|
||||
CReflector* find(unsigned int id);
|
||||
|
||||
void clock(unsigned int ms);
|
||||
|
||||
private:
|
||||
std::string m_hostsFile;
|
||||
std::vector<CReflector*> m_reflectors;
|
||||
CTimer m_timer;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* Copyright (C) 2006-2009,2012,2013,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 RingBuffer_H
|
||||
#define RingBuffer_H
|
||||
|
||||
#include "Log.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
template<class T> class CRingBuffer {
|
||||
public:
|
||||
CRingBuffer(unsigned int length, const char* name) :
|
||||
m_length(length),
|
||||
m_name(name),
|
||||
m_buffer(NULL),
|
||||
m_iPtr(0U),
|
||||
m_oPtr(0U)
|
||||
{
|
||||
assert(length > 0U);
|
||||
assert(name != NULL);
|
||||
|
||||
m_buffer = new T[length];
|
||||
|
||||
::memset(m_buffer, 0x00, m_length * sizeof(T));
|
||||
}
|
||||
|
||||
~CRingBuffer()
|
||||
{
|
||||
delete[] m_buffer;
|
||||
}
|
||||
|
||||
bool addData(const T* buffer, unsigned int nSamples)
|
||||
{
|
||||
if (nSamples >= freeSpace()) {
|
||||
LogError("%s buffer overflow, clearing the buffer. (%u >= %u)", m_name, nSamples, freeSpace());
|
||||
clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0U; i < nSamples; i++) {
|
||||
m_buffer[m_iPtr++] = buffer[i];
|
||||
|
||||
if (m_iPtr == m_length)
|
||||
m_iPtr = 0U;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool getData(T* buffer, unsigned int nSamples)
|
||||
{
|
||||
if (dataSize() < nSamples) {
|
||||
LogError("**** Underflow in %s ring buffer, %u < %u", m_name, dataSize(), nSamples);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0U; i < nSamples; i++) {
|
||||
buffer[i] = m_buffer[m_oPtr++];
|
||||
|
||||
if (m_oPtr == m_length)
|
||||
m_oPtr = 0U;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool peek(T* buffer, unsigned int nSamples)
|
||||
{
|
||||
if (dataSize() < nSamples) {
|
||||
LogError("**** Underflow peek in %s ring buffer, %u < %u", m_name, dataSize(), nSamples);
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int ptr = m_oPtr;
|
||||
for (unsigned int i = 0U; i < nSamples; i++) {
|
||||
buffer[i] = m_buffer[ptr++];
|
||||
|
||||
if (ptr == m_length)
|
||||
ptr = 0U;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_iPtr = 0U;
|
||||
m_oPtr = 0U;
|
||||
|
||||
::memset(m_buffer, 0x00, m_length * sizeof(T));
|
||||
}
|
||||
|
||||
unsigned int freeSpace() const
|
||||
{
|
||||
unsigned int len = m_length;
|
||||
|
||||
if (m_oPtr > m_iPtr)
|
||||
len = m_oPtr - m_iPtr;
|
||||
else if (m_iPtr > m_oPtr)
|
||||
len = m_length - (m_iPtr - m_oPtr);
|
||||
|
||||
if (len > m_length)
|
||||
len = 0U;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
unsigned int dataSize() const
|
||||
{
|
||||
return m_length - freeSpace();
|
||||
}
|
||||
|
||||
bool hasSpace(unsigned int length) const
|
||||
{
|
||||
return freeSpace() > length;
|
||||
}
|
||||
|
||||
bool hasData() const
|
||||
{
|
||||
return m_oPtr != m_iPtr;
|
||||
}
|
||||
|
||||
bool isEmpty() const
|
||||
{
|
||||
return m_oPtr == m_iPtr;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned int m_length;
|
||||
const char* m_name;
|
||||
T* m_buffer;
|
||||
unsigned int m_iPtr;
|
||||
unsigned int m_oPtr;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,373 @@
|
|||
/*
|
||||
* Copyright (C) 2005, 2006, 2008 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2011,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 "SHA256.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
# define SWAP(n) (n)
|
||||
#else
|
||||
# define SWAP(n) \
|
||||
(((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
|
||||
#endif
|
||||
|
||||
#define BLOCKSIZE 4096
|
||||
#if BLOCKSIZE % 64 != 0
|
||||
# error "invalid BLOCKSIZE"
|
||||
#endif
|
||||
|
||||
/* This array contains the bytes used to pad the buffer to the next
|
||||
64-byte boundary. */
|
||||
static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
|
||||
|
||||
|
||||
/*
|
||||
Takes a pointer to a 256 bit block of data (eight 32 bit ints) and
|
||||
intializes it to the start constants of the SHA256 algorithm. This
|
||||
must be called before using hash in the call to sha256_hash
|
||||
*/
|
||||
CSHA256::CSHA256() :
|
||||
m_state(NULL),
|
||||
m_total(NULL),
|
||||
m_buflen(0U),
|
||||
m_buffer(NULL)
|
||||
{
|
||||
m_state = new uint32_t[8U];
|
||||
m_total = new uint32_t[2U];
|
||||
m_buffer = new uint32_t[32U];
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
CSHA256::~CSHA256()
|
||||
{
|
||||
delete[] m_state;
|
||||
delete[] m_total;
|
||||
delete[] m_buffer;
|
||||
}
|
||||
|
||||
void CSHA256::init()
|
||||
{
|
||||
m_state[0] = 0x6a09e667UL;
|
||||
m_state[1] = 0xbb67ae85UL;
|
||||
m_state[2] = 0x3c6ef372UL;
|
||||
m_state[3] = 0xa54ff53aUL;
|
||||
m_state[4] = 0x510e527fUL;
|
||||
m_state[5] = 0x9b05688cUL;
|
||||
m_state[6] = 0x1f83d9abUL;
|
||||
m_state[7] = 0x5be0cd19UL;
|
||||
|
||||
m_total[0] = m_total[1] = 0;
|
||||
m_buflen = 0;
|
||||
}
|
||||
|
||||
/* Copy the value from v into the memory location pointed to by *cp,
|
||||
If your architecture allows unaligned access this is equivalent to
|
||||
* (uint32_t *) cp = v */
|
||||
static inline void set_uint32(unsigned char* cp, uint32_t v)
|
||||
{
|
||||
assert(cp != NULL);
|
||||
|
||||
::memcpy(cp, &v, sizeof v);
|
||||
}
|
||||
|
||||
/* Put result from CTX in first 32 bytes following RESBUF. The result
|
||||
must be in little endian byte order. */
|
||||
unsigned char* CSHA256::read(unsigned char* resbuf)
|
||||
{
|
||||
assert(resbuf != NULL);
|
||||
|
||||
for (unsigned int i = 0U; i < 8U; i++)
|
||||
set_uint32(resbuf + i * sizeof(m_state[0]), SWAP(m_state[i]));
|
||||
|
||||
return resbuf;
|
||||
}
|
||||
|
||||
/* Process the remaining bytes in the internal buffer and the usual
|
||||
prolog according to the standard and write the result to RESBUF. */
|
||||
void CSHA256::conclude()
|
||||
{
|
||||
/* Take yet unprocessed bytes into account. */
|
||||
unsigned int bytes = m_buflen;
|
||||
unsigned int size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4;
|
||||
|
||||
/* Now count remaining bytes. */
|
||||
m_total[0] += bytes;
|
||||
if (m_total[0] < bytes)
|
||||
++m_total[1];
|
||||
|
||||
/* Put the 64-bit file length in *bits* at the end of the buffer.
|
||||
Use set_uint32 rather than a simple assignment, to avoid risk of
|
||||
unaligned access. */
|
||||
set_uint32((unsigned char*)&m_buffer[size - 2], SWAP((m_total[1] << 3) | (m_total[0] >> 29)));
|
||||
set_uint32((unsigned char*)&m_buffer[size - 1], SWAP(m_total[0] << 3));
|
||||
|
||||
::memcpy(&((char*)m_buffer)[bytes], fillbuf, (size - 2) * 4 - bytes);
|
||||
|
||||
/* Process last bytes. */
|
||||
processBlock((unsigned char*)m_buffer, size * 4);
|
||||
}
|
||||
|
||||
unsigned char* CSHA256::finish(unsigned char* resbuf)
|
||||
{
|
||||
assert(resbuf != NULL);
|
||||
|
||||
conclude();
|
||||
|
||||
return read(resbuf);
|
||||
}
|
||||
|
||||
/* Compute SHA256 message digest for LEN bytes beginning at BUFFER. The
|
||||
result is always in little endian byte order, so that a byte-wise
|
||||
output yields to the wanted ASCII representation of the message
|
||||
digest. */
|
||||
unsigned char* CSHA256::buffer(const unsigned char* buffer, unsigned int len, unsigned char* resblock)
|
||||
{
|
||||
assert(buffer != NULL);
|
||||
assert(resblock != NULL);
|
||||
|
||||
/* Initialize the computation context. */
|
||||
init();
|
||||
|
||||
/* Process whole buffer but last len % 64 bytes. */
|
||||
processBytes(buffer, len);
|
||||
|
||||
/* Put result in desired memory area. */
|
||||
return finish(resblock);
|
||||
}
|
||||
|
||||
void CSHA256::processBytes(const unsigned char* buffer, unsigned int len)
|
||||
{
|
||||
assert(buffer != NULL);
|
||||
|
||||
/* When we already have some bits in our internal buffer concatenate
|
||||
both inputs first. */
|
||||
if (m_buflen != 0U) {
|
||||
unsigned int left_over = m_buflen;
|
||||
unsigned int add = 128U - left_over > len ? len : 128U - left_over;
|
||||
|
||||
::memcpy(&((char*)m_buffer)[left_over], buffer, add);
|
||||
m_buflen += add;
|
||||
|
||||
if (m_buflen > 64U) {
|
||||
processBlock((unsigned char*)m_buffer, m_buflen & ~63U);
|
||||
|
||||
m_buflen &= 63U;
|
||||
|
||||
/* The regions in the following copy operation cannot overlap. */
|
||||
::memcpy(m_buffer, &((char*)m_buffer)[(left_over + add) & ~63U], m_buflen);
|
||||
}
|
||||
|
||||
buffer += add;
|
||||
len -= add;
|
||||
}
|
||||
|
||||
/* Process available complete blocks. */
|
||||
if (len >= 64U) {
|
||||
//#if !_STRING_ARCH_unaligned
|
||||
//# define alignof(type) offsetof (struct { char c; type x; }, x)
|
||||
//# define UNALIGNED_P(p) (((unsigned int) p) % alignof (uint32_t) != 0)
|
||||
// if (UNALIGNED_P (buffer)) {
|
||||
// while (len > 64U) {
|
||||
// ::memcpy(m_buffer, buffer, 64U);
|
||||
// processBlock((unsigned char*)m_buffer, 64U);
|
||||
// buffer += 64U;
|
||||
// len -= 64U;
|
||||
// }
|
||||
// } else
|
||||
//#endif
|
||||
{
|
||||
processBlock(buffer, len & ~63U);
|
||||
buffer += (len & ~63U);
|
||||
len &= 63U;
|
||||
}
|
||||
}
|
||||
|
||||
/* Move remaining bytes in internal buffer. */
|
||||
if (len > 0U) {
|
||||
unsigned int left_over = m_buflen;
|
||||
|
||||
::memcpy(&((char*)m_buffer)[left_over], buffer, len);
|
||||
left_over += len;
|
||||
|
||||
if (left_over >= 64U) {
|
||||
processBlock((unsigned char*)m_buffer, 64U);
|
||||
left_over -= 64U;
|
||||
::memcpy(m_buffer, &m_buffer[16], left_over);
|
||||
}
|
||||
|
||||
m_buflen = left_over;
|
||||
}
|
||||
}
|
||||
|
||||
/* --- Code below is the primary difference between sha1.c and sha256.c --- */
|
||||
|
||||
/* SHA256 round constants */
|
||||
#define K(I) roundConstants[I]
|
||||
static const uint32_t roundConstants[64] = {
|
||||
0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
|
||||
0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,
|
||||
0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
|
||||
0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
|
||||
0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
|
||||
0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
|
||||
0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
|
||||
0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL,
|
||||
0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
|
||||
0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
|
||||
0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,
|
||||
0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
|
||||
0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
|
||||
0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
|
||||
0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
|
||||
0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL,
|
||||
};
|
||||
|
||||
/* Round functions. */
|
||||
#define F2(A,B,C) ( ( A & B ) | ( C & ( A | B ) ) )
|
||||
#define F1(E,F,G) ( G ^ ( E & ( F ^ G ) ) )
|
||||
|
||||
/* Process LEN bytes of BUFFER, accumulating context into CTX.
|
||||
It is assumed that LEN % 64 == 0.
|
||||
Most of this code comes from GnuPG's cipher/sha1.c. */
|
||||
|
||||
void CSHA256::processBlock(const unsigned char* buffer, unsigned int len)
|
||||
{
|
||||
assert(buffer != NULL);
|
||||
|
||||
const uint32_t* words = (uint32_t*)buffer;
|
||||
unsigned int nwords = len / sizeof(uint32_t);
|
||||
const uint32_t* endp = words + nwords;
|
||||
uint32_t x[16];
|
||||
uint32_t a = m_state[0];
|
||||
uint32_t b = m_state[1];
|
||||
uint32_t c = m_state[2];
|
||||
uint32_t d = m_state[3];
|
||||
uint32_t e = m_state[4];
|
||||
uint32_t f = m_state[5];
|
||||
uint32_t g = m_state[6];
|
||||
uint32_t h = m_state[7];
|
||||
|
||||
/* First increment the byte count. FIPS PUB 180-2 specifies the possible
|
||||
length of the file up to 2^64 bits. Here we only compute the
|
||||
number of bytes. Do a double word increment. */
|
||||
m_total[0] += len;
|
||||
if (m_total[0] < len)
|
||||
++m_total[1];
|
||||
|
||||
#define rol(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
|
||||
#define S0(x) (rol(x,25)^rol(x,14)^(x>>3))
|
||||
#define S1(x) (rol(x,15)^rol(x,13)^(x>>10))
|
||||
#define SS0(x) (rol(x,30)^rol(x,19)^rol(x,10))
|
||||
#define SS1(x) (rol(x,26)^rol(x,21)^rol(x,7))
|
||||
|
||||
#define M(I) (tm = S1(x[(I-2)&0x0f]) + x[(I-7)&0x0f] + S0(x[(I-15)&0x0f]) + x[I&0x0f], x[I&0x0f] = tm)
|
||||
|
||||
#define R(A,B,C,D,E,F,G,H,K,M) do { t0 = SS0(A) + F2(A,B,C); \
|
||||
t1 = H + SS1(E) + F1(E,F,G) + K + M; \
|
||||
D += t1; H = t0 + t1; \
|
||||
} while(0)
|
||||
|
||||
while (words < endp) {
|
||||
uint32_t tm;
|
||||
uint32_t t0, t1;
|
||||
/* FIXME: see sha1.c for a better implementation. */
|
||||
for (unsigned int t = 0U; t < 16U; t++) {
|
||||
x[t] = SWAP(*words);
|
||||
words++;
|
||||
}
|
||||
|
||||
R( a, b, c, d, e, f, g, h, K( 0), x[ 0] );
|
||||
R( h, a, b, c, d, e, f, g, K( 1), x[ 1] );
|
||||
R( g, h, a, b, c, d, e, f, K( 2), x[ 2] );
|
||||
R( f, g, h, a, b, c, d, e, K( 3), x[ 3] );
|
||||
R( e, f, g, h, a, b, c, d, K( 4), x[ 4] );
|
||||
R( d, e, f, g, h, a, b, c, K( 5), x[ 5] );
|
||||
R( c, d, e, f, g, h, a, b, K( 6), x[ 6] );
|
||||
R( b, c, d, e, f, g, h, a, K( 7), x[ 7] );
|
||||
R( a, b, c, d, e, f, g, h, K( 8), x[ 8] );
|
||||
R( h, a, b, c, d, e, f, g, K( 9), x[ 9] );
|
||||
R( g, h, a, b, c, d, e, f, K(10), x[10] );
|
||||
R( f, g, h, a, b, c, d, e, K(11), x[11] );
|
||||
R( e, f, g, h, a, b, c, d, K(12), x[12] );
|
||||
R( d, e, f, g, h, a, b, c, K(13), x[13] );
|
||||
R( c, d, e, f, g, h, a, b, K(14), x[14] );
|
||||
R( b, c, d, e, f, g, h, a, K(15), x[15] );
|
||||
R( a, b, c, d, e, f, g, h, K(16), M(16) );
|
||||
R( h, a, b, c, d, e, f, g, K(17), M(17) );
|
||||
R( g, h, a, b, c, d, e, f, K(18), M(18) );
|
||||
R( f, g, h, a, b, c, d, e, K(19), M(19) );
|
||||
R( e, f, g, h, a, b, c, d, K(20), M(20) );
|
||||
R( d, e, f, g, h, a, b, c, K(21), M(21) );
|
||||
R( c, d, e, f, g, h, a, b, K(22), M(22) );
|
||||
R( b, c, d, e, f, g, h, a, K(23), M(23) );
|
||||
R( a, b, c, d, e, f, g, h, K(24), M(24) );
|
||||
R( h, a, b, c, d, e, f, g, K(25), M(25) );
|
||||
R( g, h, a, b, c, d, e, f, K(26), M(26) );
|
||||
R( f, g, h, a, b, c, d, e, K(27), M(27) );
|
||||
R( e, f, g, h, a, b, c, d, K(28), M(28) );
|
||||
R( d, e, f, g, h, a, b, c, K(29), M(29) );
|
||||
R( c, d, e, f, g, h, a, b, K(30), M(30) );
|
||||
R( b, c, d, e, f, g, h, a, K(31), M(31) );
|
||||
R( a, b, c, d, e, f, g, h, K(32), M(32) );
|
||||
R( h, a, b, c, d, e, f, g, K(33), M(33) );
|
||||
R( g, h, a, b, c, d, e, f, K(34), M(34) );
|
||||
R( f, g, h, a, b, c, d, e, K(35), M(35) );
|
||||
R( e, f, g, h, a, b, c, d, K(36), M(36) );
|
||||
R( d, e, f, g, h, a, b, c, K(37), M(37) );
|
||||
R( c, d, e, f, g, h, a, b, K(38), M(38) );
|
||||
R( b, c, d, e, f, g, h, a, K(39), M(39) );
|
||||
R( a, b, c, d, e, f, g, h, K(40), M(40) );
|
||||
R( h, a, b, c, d, e, f, g, K(41), M(41) );
|
||||
R( g, h, a, b, c, d, e, f, K(42), M(42) );
|
||||
R( f, g, h, a, b, c, d, e, K(43), M(43) );
|
||||
R( e, f, g, h, a, b, c, d, K(44), M(44) );
|
||||
R( d, e, f, g, h, a, b, c, K(45), M(45) );
|
||||
R( c, d, e, f, g, h, a, b, K(46), M(46) );
|
||||
R( b, c, d, e, f, g, h, a, K(47), M(47) );
|
||||
R( a, b, c, d, e, f, g, h, K(48), M(48) );
|
||||
R( h, a, b, c, d, e, f, g, K(49), M(49) );
|
||||
R( g, h, a, b, c, d, e, f, K(50), M(50) );
|
||||
R( f, g, h, a, b, c, d, e, K(51), M(51) );
|
||||
R( e, f, g, h, a, b, c, d, K(52), M(52) );
|
||||
R( d, e, f, g, h, a, b, c, K(53), M(53) );
|
||||
R( c, d, e, f, g, h, a, b, K(54), M(54) );
|
||||
R( b, c, d, e, f, g, h, a, K(55), M(55) );
|
||||
R( a, b, c, d, e, f, g, h, K(56), M(56) );
|
||||
R( h, a, b, c, d, e, f, g, K(57), M(57) );
|
||||
R( g, h, a, b, c, d, e, f, K(58), M(58) );
|
||||
R( f, g, h, a, b, c, d, e, K(59), M(59) );
|
||||
R( e, f, g, h, a, b, c, d, K(60), M(60) );
|
||||
R( d, e, f, g, h, a, b, c, K(61), M(61) );
|
||||
R( c, d, e, f, g, h, a, b, K(62), M(62) );
|
||||
R( b, c, d, e, f, g, h, a, K(63), M(63) );
|
||||
|
||||
a = m_state[0] += a;
|
||||
b = m_state[1] += b;
|
||||
c = m_state[2] += c;
|
||||
d = m_state[3] += d;
|
||||
e = m_state[4] += e;
|
||||
f = m_state[5] += f;
|
||||
g = m_state[6] += g;
|
||||
h = m_state[7] += h;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright (C) 2005, 2006, 2008, 2009 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2011,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 SHA256_H
|
||||
#define SHA256_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum {
|
||||
SHA256_DIGEST_SIZE = 256 / 8
|
||||
};
|
||||
|
||||
class CSHA256 {
|
||||
public:
|
||||
CSHA256();
|
||||
~CSHA256();
|
||||
|
||||
/* Starting with the result of former calls of this function (or the
|
||||
initialization function update the context for the next LEN bytes
|
||||
starting at BUFFER.
|
||||
It is necessary that LEN is a multiple of 64!!! */
|
||||
void processBlock(const unsigned char* buffer, unsigned int len);
|
||||
|
||||
/* Starting with the result of former calls of this function (or the
|
||||
initialization function update the context for the next LEN bytes
|
||||
starting at BUFFER.
|
||||
It is NOT required that LEN is a multiple of 64. */
|
||||
void processBytes(const unsigned char* buffer, unsigned int len);
|
||||
|
||||
/* Process the remaining bytes in the buffer and put result from CTX
|
||||
in first 32 bytes following RESBUF. The result is always in little
|
||||
endian byte order, so that a byte-wise output yields to the wanted
|
||||
ASCII representation of the message digest. */
|
||||
unsigned char* finish(unsigned char* resbuf);
|
||||
|
||||
/* Put result from CTX in first 32 bytes following RESBUF. The result is
|
||||
always in little endian byte order, so that a byte-wise output yields
|
||||
to the wanted ASCII representation of the message digest. */
|
||||
unsigned char* read(unsigned char* resbuf);
|
||||
|
||||
/* Compute SHA256 message digest for LEN bytes beginning at BUFFER. The
|
||||
result is always in little endian byte order, so that a byte-wise
|
||||
output yields to the wanted ASCII representation of the message
|
||||
digest. */
|
||||
unsigned char* buffer(const unsigned char* buffer, unsigned int len, unsigned char* resblock);
|
||||
|
||||
private:
|
||||
uint32_t* m_state;
|
||||
uint32_t* m_total;
|
||||
unsigned int m_buflen;
|
||||
uint32_t* m_buffer;
|
||||
|
||||
void init();
|
||||
void conclude();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* Copyright (C) 2015,2016,2018 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 "StopWatch.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
|
||||
CStopWatch::CStopWatch() :
|
||||
m_frequencyS(),
|
||||
m_frequencyMS(),
|
||||
m_start()
|
||||
{
|
||||
::QueryPerformanceFrequency(&m_frequencyS);
|
||||
|
||||
m_frequencyMS.QuadPart = m_frequencyS.QuadPart / 1000ULL;
|
||||
}
|
||||
|
||||
CStopWatch::~CStopWatch()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned long long CStopWatch::time() const
|
||||
{
|
||||
LARGE_INTEGER now;
|
||||
::QueryPerformanceCounter(&now);
|
||||
|
||||
return (unsigned long long)(now.QuadPart / m_frequencyMS.QuadPart);
|
||||
}
|
||||
|
||||
unsigned long long CStopWatch::start()
|
||||
{
|
||||
::QueryPerformanceCounter(&m_start);
|
||||
|
||||
return (unsigned long long)(m_start.QuadPart / m_frequencyS.QuadPart);
|
||||
}
|
||||
|
||||
unsigned int CStopWatch::elapsed()
|
||||
{
|
||||
LARGE_INTEGER now;
|
||||
::QueryPerformanceCounter(&now);
|
||||
|
||||
LARGE_INTEGER temp;
|
||||
temp.QuadPart = (now.QuadPart - m_start.QuadPart) * 1000;
|
||||
|
||||
return (unsigned int)(temp.QuadPart / m_frequencyS.QuadPart);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
|
||||
CStopWatch::CStopWatch() :
|
||||
m_startMS(0ULL)
|
||||
{
|
||||
}
|
||||
|
||||
CStopWatch::~CStopWatch()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned long long CStopWatch::time() const
|
||||
{
|
||||
struct timeval now;
|
||||
::gettimeofday(&now, NULL);
|
||||
|
||||
return now.tv_sec * 1000ULL + now.tv_usec / 1000ULL;
|
||||
}
|
||||
|
||||
unsigned long long CStopWatch::start()
|
||||
{
|
||||
struct timespec now;
|
||||
::clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
||||
m_startMS = now.tv_sec * 1000ULL + now.tv_nsec / 1000000ULL;
|
||||
|
||||
return m_startMS;
|
||||
}
|
||||
|
||||
unsigned int CStopWatch::elapsed()
|
||||
{
|
||||
struct timespec now;
|
||||
::clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
||||
unsigned long long nowMS = now.tv_sec * 1000ULL + now.tv_nsec / 1000000ULL;
|
||||
|
||||
return nowMS - m_startMS;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (C) 2015,2016,2018 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(STOPWATCH_H)
|
||||
#define STOPWATCH_H
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
class CStopWatch
|
||||
{
|
||||
public:
|
||||
CStopWatch();
|
||||
~CStopWatch();
|
||||
|
||||
unsigned long long time() const;
|
||||
|
||||
unsigned long long start();
|
||||
unsigned int elapsed();
|
||||
|
||||
private:
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
LARGE_INTEGER m_frequencyS;
|
||||
LARGE_INTEGER m_frequencyMS;
|
||||
LARGE_INTEGER m_start;
|
||||
#else
|
||||
unsigned long long m_startMS;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||
*
|
||||
* 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 "Sync.h"
|
||||
|
||||
#include "DMRDefines.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
void CSync::addDMRDataSync(unsigned char* data, bool duplex)
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
if (duplex) {
|
||||
for (unsigned int i = 0U; i < 7U; i++)
|
||||
data[i + 13U] = (data[i + 13U] & ~SYNC_MASK[i]) | BS_SOURCED_DATA_SYNC[i];
|
||||
} else {
|
||||
for (unsigned int i = 0U; i < 7U; i++)
|
||||
data[i + 13U] = (data[i + 13U] & ~SYNC_MASK[i]) | MS_SOURCED_DATA_SYNC[i];
|
||||
}
|
||||
}
|
||||
|
||||
void CSync::addDMRAudioSync(unsigned char* data, bool duplex)
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
if (duplex) {
|
||||
for (unsigned int i = 0U; i < 7U; i++)
|
||||
data[i + 13U] = (data[i + 13U] & ~SYNC_MASK[i]) | BS_SOURCED_AUDIO_SYNC[i];
|
||||
} else {
|
||||
for (unsigned int i = 0U; i < 7U; i++)
|
||||
data[i + 13U] = (data[i + 13U] & ~SYNC_MASK[i]) | MS_SOURCED_AUDIO_SYNC[i];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||
*
|
||||
* 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(SYNC_H)
|
||||
#define SYNC_H
|
||||
|
||||
class CSync
|
||||
{
|
||||
public:
|
||||
static void addDMRDataSync(unsigned char* data, bool duplex);
|
||||
static void addDMRAudioSync(unsigned char* data, bool duplex);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* 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 "Thread.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
|
||||
CThread::CThread() :
|
||||
m_handle()
|
||||
{
|
||||
}
|
||||
|
||||
CThread::~CThread()
|
||||
{
|
||||
}
|
||||
|
||||
bool CThread::run()
|
||||
{
|
||||
m_handle = ::CreateThread(NULL, 0, &helper, this, 0, NULL);
|
||||
|
||||
return m_handle != NULL;
|
||||
}
|
||||
|
||||
|
||||
void CThread::wait()
|
||||
{
|
||||
::WaitForSingleObject(m_handle, INFINITE);
|
||||
|
||||
::CloseHandle(m_handle);
|
||||
}
|
||||
|
||||
|
||||
DWORD CThread::helper(LPVOID arg)
|
||||
{
|
||||
CThread* p = (CThread*)arg;
|
||||
|
||||
p->entry();
|
||||
|
||||
return 0UL;
|
||||
}
|
||||
|
||||
void CThread::sleep(unsigned int ms)
|
||||
{
|
||||
::Sleep(ms);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
CThread::CThread() :
|
||||
m_thread()
|
||||
{
|
||||
}
|
||||
|
||||
CThread::~CThread()
|
||||
{
|
||||
}
|
||||
|
||||
bool CThread::run()
|
||||
{
|
||||
return ::pthread_create(&m_thread, NULL, helper, this) == 0;
|
||||
}
|
||||
|
||||
|
||||
void CThread::wait()
|
||||
{
|
||||
::pthread_join(m_thread, NULL);
|
||||
}
|
||||
|
||||
|
||||
void* CThread::helper(void* arg)
|
||||
{
|
||||
CThread* p = (CThread*)arg;
|
||||
|
||||
p->entry();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CThread::sleep(unsigned int ms)
|
||||
{
|
||||
::usleep(ms * 1000);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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(THREAD_H)
|
||||
#define THREAD_H
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
class CThread
|
||||
{
|
||||
public:
|
||||
CThread();
|
||||
virtual ~CThread();
|
||||
|
||||
virtual bool run();
|
||||
|
||||
virtual void entry() = 0;
|
||||
|
||||
virtual void wait();
|
||||
|
||||
static void sleep(unsigned int ms);
|
||||
|
||||
private:
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
HANDLE m_handle;
|
||||
#else
|
||||
pthread_t m_thread;
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
static DWORD __stdcall helper(LPVOID arg);
|
||||
#else
|
||||
static void* helper(void* arg);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright (C) 2009,2010,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 "Timer.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
CTimer::CTimer(unsigned int ticksPerSec, unsigned int secs, unsigned int msecs) :
|
||||
m_ticksPerSec(ticksPerSec),
|
||||
m_timeout(0U),
|
||||
m_timer(0U)
|
||||
{
|
||||
assert(ticksPerSec > 0U);
|
||||
|
||||
if (secs > 0U || msecs > 0U) {
|
||||
// m_timeout = ((secs * 1000U + msecs) * m_ticksPerSec) / 1000U + 1U;
|
||||
unsigned long long temp = (secs * 1000ULL + msecs) * m_ticksPerSec;
|
||||
m_timeout = (unsigned int)(temp / 1000ULL + 1ULL);
|
||||
}
|
||||
}
|
||||
|
||||
CTimer::~CTimer()
|
||||
{
|
||||
}
|
||||
|
||||
void CTimer::setTimeout(unsigned int secs, unsigned int msecs)
|
||||
{
|
||||
if (secs > 0U || msecs > 0U) {
|
||||
// m_timeout = ((secs * 1000U + msecs) * m_ticksPerSec) / 1000U + 1U;
|
||||
unsigned long long temp = (secs * 1000ULL + msecs) * m_ticksPerSec;
|
||||
m_timeout = (unsigned int)(temp / 1000ULL + 1ULL);
|
||||
} else {
|
||||
m_timeout = 0U;
|
||||
m_timer = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int CTimer::getTimeout() const
|
||||
{
|
||||
if (m_timeout == 0U)
|
||||
return 0U;
|
||||
|
||||
return (m_timeout - 1U) / m_ticksPerSec;
|
||||
}
|
||||
|
||||
unsigned int CTimer::getTimer() const
|
||||
{
|
||||
if (m_timer == 0U)
|
||||
return 0U;
|
||||
|
||||
return (m_timer - 1U) / m_ticksPerSec;
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright (C) 2009,2010,2011,2014 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 Timer_H
|
||||
#define Timer_H
|
||||
|
||||
class CTimer {
|
||||
public:
|
||||
CTimer(unsigned int ticksPerSec, unsigned int secs = 0U, unsigned int msecs = 0U);
|
||||
~CTimer();
|
||||
|
||||
void setTimeout(unsigned int secs, unsigned int msecs = 0U);
|
||||
|
||||
unsigned int getTimeout() const;
|
||||
unsigned int getTimer() const;
|
||||
|
||||
unsigned int getRemaining()
|
||||
{
|
||||
if (m_timeout == 0U || m_timer == 0U)
|
||||
return 0U;
|
||||
|
||||
if (m_timer >= m_timeout)
|
||||
return 0U;
|
||||
|
||||
return (m_timeout - m_timer) / m_ticksPerSec;
|
||||
}
|
||||
|
||||
bool isRunning()
|
||||
{
|
||||
return m_timer > 0U;
|
||||
}
|
||||
|
||||
void start(unsigned int secs, unsigned int msecs = 0U)
|
||||
{
|
||||
setTimeout(secs, msecs);
|
||||
|
||||
start();
|
||||
}
|
||||
|
||||
void start()
|
||||
{
|
||||
if (m_timeout > 0U)
|
||||
m_timer = 1U;
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
m_timer = 0U;
|
||||
}
|
||||
|
||||
bool hasExpired()
|
||||
{
|
||||
if (m_timeout == 0U || m_timer == 0U)
|
||||
return false;
|
||||
|
||||
if (m_timer >= m_timeout)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void clock(unsigned int ticks = 1U)
|
||||
{
|
||||
if (m_timer > 0U && m_timeout > 0U)
|
||||
m_timer += ticks;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned int m_ticksPerSec;
|
||||
unsigned int m_timeout;
|
||||
unsigned int m_timer;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
* Copyright (C) 2006-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 "UDPSocket.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#endif
|
||||
|
||||
|
||||
CUDPSocket::CUDPSocket(const std::string& address, unsigned int port) :
|
||||
m_address(address),
|
||||
m_port(port),
|
||||
m_fd(-1)
|
||||
{
|
||||
assert(!address.empty());
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
WSAData data;
|
||||
int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data);
|
||||
if (wsaRet != 0)
|
||||
LogError("Error from WSAStartup");
|
||||
#endif
|
||||
}
|
||||
|
||||
CUDPSocket::CUDPSocket(unsigned int port) :
|
||||
m_address(),
|
||||
m_port(port),
|
||||
m_fd(-1)
|
||||
{
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
WSAData data;
|
||||
int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data);
|
||||
if (wsaRet != 0)
|
||||
LogError("Error from WSAStartup");
|
||||
#endif
|
||||
}
|
||||
|
||||
CUDPSocket::~CUDPSocket()
|
||||
{
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
::WSACleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
in_addr CUDPSocket::lookup(const std::string& hostname)
|
||||
{
|
||||
in_addr addr;
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
unsigned long address = ::inet_addr(hostname.c_str());
|
||||
if (address != INADDR_NONE && address != INADDR_ANY) {
|
||||
addr.s_addr = address;
|
||||
return addr;
|
||||
}
|
||||
|
||||
struct hostent* hp = ::gethostbyname(hostname.c_str());
|
||||
if (hp != NULL) {
|
||||
::memcpy(&addr, hp->h_addr_list[0], sizeof(struct in_addr));
|
||||
return addr;
|
||||
}
|
||||
|
||||
LogError("Cannot find address for host %s", hostname.c_str());
|
||||
|
||||
addr.s_addr = INADDR_NONE;
|
||||
return addr;
|
||||
#else
|
||||
in_addr_t address = ::inet_addr(hostname.c_str());
|
||||
if (address != in_addr_t(-1)) {
|
||||
addr.s_addr = address;
|
||||
return addr;
|
||||
}
|
||||
|
||||
struct hostent* hp = ::gethostbyname(hostname.c_str());
|
||||
if (hp != NULL) {
|
||||
::memcpy(&addr, hp->h_addr_list[0], sizeof(struct in_addr));
|
||||
return addr;
|
||||
}
|
||||
|
||||
LogError("Cannot find address for host %s", hostname.c_str());
|
||||
|
||||
addr.s_addr = INADDR_NONE;
|
||||
return addr;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool CUDPSocket::open()
|
||||
{
|
||||
m_fd = ::socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (m_fd < 0) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
LogError("Cannot create the UDP socket, err: %lu", ::GetLastError());
|
||||
#else
|
||||
LogError("Cannot create the UDP socket, err: %d", errno);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_port > 0U) {
|
||||
sockaddr_in addr;
|
||||
::memset(&addr, 0x00, sizeof(sockaddr_in));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(m_port);
|
||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
if (!m_address.empty()) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
addr.sin_addr.s_addr = ::inet_addr(m_address.c_str());
|
||||
#else
|
||||
addr.sin_addr.s_addr = ::inet_addr(m_address.c_str());
|
||||
#endif
|
||||
if (addr.sin_addr.s_addr == INADDR_NONE) {
|
||||
LogError("The local address is invalid - %s", m_address.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int reuse = 1;
|
||||
if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
LogError("Cannot set the UDP socket option, err: %lu", ::GetLastError());
|
||||
#else
|
||||
LogError("Cannot set the UDP socket option, err: %d", errno);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
if (::bind(m_fd, (sockaddr*)&addr, sizeof(sockaddr_in)) == -1) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
LogError("Cannot bind the UDP address, err: %lu", ::GetLastError());
|
||||
#else
|
||||
LogError("Cannot bind the UDP address, err: %d", errno);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int CUDPSocket::read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port)
|
||||
{
|
||||
assert(buffer != NULL);
|
||||
assert(length > 0U);
|
||||
|
||||
// Check that the readfrom() won't block
|
||||
fd_set readFds;
|
||||
FD_ZERO(&readFds);
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
FD_SET((unsigned int)m_fd, &readFds);
|
||||
#else
|
||||
FD_SET(m_fd, &readFds);
|
||||
#endif
|
||||
|
||||
// Return immediately
|
||||
timeval tv;
|
||||
tv.tv_sec = 0L;
|
||||
tv.tv_usec = 0L;
|
||||
|
||||
int ret = ::select(m_fd + 1, &readFds, NULL, NULL, &tv);
|
||||
if (ret < 0) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
LogError("Error returned from UDP select, err: %lu", ::GetLastError());
|
||||
#else
|
||||
LogError("Error returned from UDP select, err: %d", errno);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
return 0;
|
||||
|
||||
sockaddr_in addr;
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
int size = sizeof(sockaddr_in);
|
||||
#else
|
||||
socklen_t size = sizeof(sockaddr_in);
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
int len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&addr, &size);
|
||||
#else
|
||||
ssize_t len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&addr, &size);
|
||||
#endif
|
||||
if (len <= 0) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
LogError("Error returned from recvfrom, err: %lu", ::GetLastError());
|
||||
#else
|
||||
LogError("Error returned from recvfrom, err: %d", errno);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
address = addr.sin_addr;
|
||||
port = ntohs(addr.sin_port);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const in_addr& address, unsigned int port)
|
||||
{
|
||||
assert(buffer != NULL);
|
||||
assert(length > 0U);
|
||||
|
||||
sockaddr_in addr;
|
||||
::memset(&addr, 0x00, sizeof(sockaddr_in));
|
||||
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr = address;
|
||||
addr.sin_port = htons(port);
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
int ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&addr, sizeof(sockaddr_in));
|
||||
#else
|
||||
ssize_t ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&addr, sizeof(sockaddr_in));
|
||||
#endif
|
||||
if (ret < 0) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
LogError("Error returned from sendto, err: %lu", ::GetLastError());
|
||||
#else
|
||||
LogError("Error returned from sendto, err: %d", errno);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
if (ret != int(length))
|
||||
return false;
|
||||
#else
|
||||
if (ret != ssize_t(length))
|
||||
return false;
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CUDPSocket::close()
|
||||
{
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
::closesocket(m_fd);
|
||||
#else
|
||||
::close(m_fd);
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2011,2013,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 UDPSocket_H
|
||||
#define UDPSocket_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
#include <netdb.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#else
|
||||
#include <winsock.h>
|
||||
#endif
|
||||
|
||||
class CUDPSocket {
|
||||
public:
|
||||
CUDPSocket(const std::string& address, unsigned int port = 0U);
|
||||
CUDPSocket(unsigned int port = 0U);
|
||||
~CUDPSocket();
|
||||
|
||||
bool open();
|
||||
|
||||
int read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port);
|
||||
bool write(const unsigned char* buffer, unsigned int length, const in_addr& address, unsigned int port);
|
||||
|
||||
void close();
|
||||
|
||||
static in_addr lookup(const std::string& hostName);
|
||||
|
||||
private:
|
||||
std::string m_address;
|
||||
unsigned short m_port;
|
||||
int m_fd;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* Copyright (C) 2009,2014,2015,2016 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; version 2 of the License.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "Utils.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
void CUtils::dump(const std::string& title, const unsigned char* data, unsigned int length)
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
dump(2U, title, data, length);
|
||||
}
|
||||
|
||||
void CUtils::dump(int level, const std::string& title, const unsigned char* data, unsigned int length)
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
::Log(level, "%s", title.c_str());
|
||||
|
||||
unsigned int offset = 0U;
|
||||
|
||||
while (length > 0U) {
|
||||
std::string output;
|
||||
|
||||
unsigned int bytes = (length > 16U) ? 16U : length;
|
||||
|
||||
for (unsigned i = 0U; i < bytes; i++) {
|
||||
char temp[10U];
|
||||
::sprintf(temp, "%02X ", data[offset + i]);
|
||||
output += temp;
|
||||
}
|
||||
|
||||
for (unsigned int i = bytes; i < 16U; i++)
|
||||
output += " ";
|
||||
|
||||
output += " *";
|
||||
|
||||
for (unsigned i = 0U; i < bytes; i++) {
|
||||
unsigned char c = data[offset + i];
|
||||
|
||||
if (::isprint(c))
|
||||
output += c;
|
||||
else
|
||||
output += '.';
|
||||
}
|
||||
|
||||
output += '*';
|
||||
|
||||
::Log(level, "%04X: %s", offset, output.c_str());
|
||||
|
||||
offset += 16U;
|
||||
|
||||
if (length >= 16U)
|
||||
length -= 16U;
|
||||
else
|
||||
length = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
void CUtils::dump(const std::string& title, const bool* bits, unsigned int length)
|
||||
{
|
||||
assert(bits != NULL);
|
||||
|
||||
dump(2U, title, bits, length);
|
||||
}
|
||||
|
||||
void CUtils::dump(int level, const std::string& title, const bool* bits, unsigned int length)
|
||||
{
|
||||
assert(bits != NULL);
|
||||
|
||||
unsigned char bytes[100U];
|
||||
unsigned int nBytes = 0U;
|
||||
for (unsigned int n = 0U; n < length; n += 8U, nBytes++)
|
||||
bitsToByteBE(bits + n, bytes[nBytes]);
|
||||
|
||||
dump(level, title, bytes, nBytes);
|
||||
}
|
||||
|
||||
void CUtils::byteToBitsBE(unsigned char byte, bool* bits)
|
||||
{
|
||||
assert(bits != NULL);
|
||||
|
||||
bits[0U] = (byte & 0x80U) == 0x80U;
|
||||
bits[1U] = (byte & 0x40U) == 0x40U;
|
||||
bits[2U] = (byte & 0x20U) == 0x20U;
|
||||
bits[3U] = (byte & 0x10U) == 0x10U;
|
||||
bits[4U] = (byte & 0x08U) == 0x08U;
|
||||
bits[5U] = (byte & 0x04U) == 0x04U;
|
||||
bits[6U] = (byte & 0x02U) == 0x02U;
|
||||
bits[7U] = (byte & 0x01U) == 0x01U;
|
||||
}
|
||||
|
||||
void CUtils::byteToBitsLE(unsigned char byte, bool* bits)
|
||||
{
|
||||
assert(bits != NULL);
|
||||
|
||||
bits[0U] = (byte & 0x01U) == 0x01U;
|
||||
bits[1U] = (byte & 0x02U) == 0x02U;
|
||||
bits[2U] = (byte & 0x04U) == 0x04U;
|
||||
bits[3U] = (byte & 0x08U) == 0x08U;
|
||||
bits[4U] = (byte & 0x10U) == 0x10U;
|
||||
bits[5U] = (byte & 0x20U) == 0x20U;
|
||||
bits[6U] = (byte & 0x40U) == 0x40U;
|
||||
bits[7U] = (byte & 0x80U) == 0x80U;
|
||||
}
|
||||
|
||||
void CUtils::bitsToByteBE(const bool* bits, unsigned char& byte)
|
||||
{
|
||||
assert(bits != NULL);
|
||||
|
||||
byte = bits[0U] ? 0x80U : 0x00U;
|
||||
byte |= bits[1U] ? 0x40U : 0x00U;
|
||||
byte |= bits[2U] ? 0x20U : 0x00U;
|
||||
byte |= bits[3U] ? 0x10U : 0x00U;
|
||||
byte |= bits[4U] ? 0x08U : 0x00U;
|
||||
byte |= bits[5U] ? 0x04U : 0x00U;
|
||||
byte |= bits[6U] ? 0x02U : 0x00U;
|
||||
byte |= bits[7U] ? 0x01U : 0x00U;
|
||||
}
|
||||
|
||||
void CUtils::bitsToByteLE(const bool* bits, unsigned char& byte)
|
||||
{
|
||||
assert(bits != NULL);
|
||||
|
||||
byte = bits[0U] ? 0x01U : 0x00U;
|
||||
byte |= bits[1U] ? 0x02U : 0x00U;
|
||||
byte |= bits[2U] ? 0x04U : 0x00U;
|
||||
byte |= bits[3U] ? 0x08U : 0x00U;
|
||||
byte |= bits[4U] ? 0x10U : 0x00U;
|
||||
byte |= bits[5U] ? 0x20U : 0x00U;
|
||||
byte |= bits[6U] ? 0x40U : 0x00U;
|
||||
byte |= bits[7U] ? 0x80U : 0x00U;
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (C) 2009,2014,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; version 2 of the License.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef Utils_H
|
||||
#define Utils_H
|
||||
|
||||
#include <string>
|
||||
|
||||
class CUtils {
|
||||
public:
|
||||
static void dump(const std::string& title, const unsigned char* data, unsigned int length);
|
||||
static void dump(int level, const std::string& title, const unsigned char* data, unsigned int length);
|
||||
|
||||
static void dump(const std::string& title, const bool* bits, unsigned int length);
|
||||
static void dump(int level, const std::string& title, const bool* bits, unsigned int length);
|
||||
|
||||
static void byteToBitsBE(unsigned char byte, bool* bits);
|
||||
static void byteToBitsLE(unsigned char byte, bool* bits);
|
||||
|
||||
static void bitsToByteBE(const bool* bits, unsigned char& byte);
|
||||
static void bitsToByteLE(const bool* bits, unsigned char& byte);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||
*
|
||||
* 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(VERSION_H)
|
||||
#define VERSION_H
|
||||
|
||||
const char* VERSION = "20180923";
|
||||
|
||||
#endif
|
|
@ -0,0 +1,964 @@
|
|||
/*
|
||||
* This intermediary file and the files that used to create it are under
|
||||
* The LGPL. See the file COPYING.
|
||||
*/
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
/* codebook/lsp1.txt */
|
||||
static float codes00[] =
|
||||
{
|
||||
225,
|
||||
250,
|
||||
275,
|
||||
300,
|
||||
325,
|
||||
350,
|
||||
375,
|
||||
400,
|
||||
425,
|
||||
450,
|
||||
475,
|
||||
500,
|
||||
525,
|
||||
550,
|
||||
575,
|
||||
600
|
||||
};
|
||||
/* codebook/lsp2.txt */
|
||||
static float codes01[] =
|
||||
{
|
||||
325,
|
||||
350,
|
||||
375,
|
||||
400,
|
||||
425,
|
||||
450,
|
||||
475,
|
||||
500,
|
||||
525,
|
||||
550,
|
||||
575,
|
||||
600,
|
||||
625,
|
||||
650,
|
||||
675,
|
||||
700
|
||||
};
|
||||
/* codebook/lsp3.txt */
|
||||
static float codes02[] =
|
||||
{
|
||||
500,
|
||||
550,
|
||||
600,
|
||||
650,
|
||||
700,
|
||||
750,
|
||||
800,
|
||||
850,
|
||||
900,
|
||||
950,
|
||||
1000,
|
||||
1050,
|
||||
1100,
|
||||
1150,
|
||||
1200,
|
||||
1250
|
||||
};
|
||||
/* codebook/lsp4.txt */
|
||||
static float codes03[] =
|
||||
{
|
||||
700,
|
||||
800,
|
||||
900,
|
||||
1000,
|
||||
1100,
|
||||
1200,
|
||||
1300,
|
||||
1400,
|
||||
1500,
|
||||
1600,
|
||||
1700,
|
||||
1800,
|
||||
1900,
|
||||
2000,
|
||||
2100,
|
||||
2200
|
||||
};
|
||||
/* codebook/lsp5.txt */
|
||||
static float codes04[] =
|
||||
{
|
||||
950,
|
||||
1050,
|
||||
1150,
|
||||
1250,
|
||||
1350,
|
||||
1450,
|
||||
1550,
|
||||
1650,
|
||||
1750,
|
||||
1850,
|
||||
1950,
|
||||
2050,
|
||||
2150,
|
||||
2250,
|
||||
2350,
|
||||
2450
|
||||
};
|
||||
/* codebook/lsp6.txt */
|
||||
static float codes05[] =
|
||||
{
|
||||
1100,
|
||||
1200,
|
||||
1300,
|
||||
1400,
|
||||
1500,
|
||||
1600,
|
||||
1700,
|
||||
1800,
|
||||
1900,
|
||||
2000,
|
||||
2100,
|
||||
2200,
|
||||
2300,
|
||||
2400,
|
||||
2500,
|
||||
2600
|
||||
};
|
||||
/* codebook/lsp7.txt */
|
||||
static float codes06[] =
|
||||
{
|
||||
1500,
|
||||
1600,
|
||||
1700,
|
||||
1800,
|
||||
1900,
|
||||
2000,
|
||||
2100,
|
||||
2200,
|
||||
2300,
|
||||
2400,
|
||||
2500,
|
||||
2600,
|
||||
2700,
|
||||
2800,
|
||||
2900,
|
||||
3000
|
||||
};
|
||||
/* codebook/lsp8.txt */
|
||||
static float codes07[] =
|
||||
{
|
||||
2300,
|
||||
2400,
|
||||
2500,
|
||||
2600,
|
||||
2700,
|
||||
2800,
|
||||
2900,
|
||||
3000
|
||||
};
|
||||
/* codebook/lsp9.txt */
|
||||
static float codes08[] =
|
||||
{
|
||||
2500,
|
||||
2600,
|
||||
2700,
|
||||
2800,
|
||||
2900,
|
||||
3000,
|
||||
3100,
|
||||
3200
|
||||
};
|
||||
/* codebook/lsp10.txt */
|
||||
static float codes09[] =
|
||||
{
|
||||
2900,
|
||||
3100,
|
||||
3300,
|
||||
3500
|
||||
};
|
||||
|
||||
const struct lsp_codebook lsp_cb[] =
|
||||
{
|
||||
/* codebook/lsp1.txt */
|
||||
{
|
||||
1,
|
||||
4,
|
||||
16,
|
||||
codes00
|
||||
},
|
||||
/* codebook/lsp2.txt */
|
||||
{
|
||||
1,
|
||||
4,
|
||||
16,
|
||||
codes01
|
||||
},
|
||||
/* codebook/lsp3.txt */
|
||||
{
|
||||
1,
|
||||
4,
|
||||
16,
|
||||
codes02
|
||||
},
|
||||
/* codebook/lsp4.txt */
|
||||
{
|
||||
1,
|
||||
4,
|
||||
16,
|
||||
codes03
|
||||
},
|
||||
/* codebook/lsp5.txt */
|
||||
{
|
||||
1,
|
||||
4,
|
||||
16,
|
||||
codes04
|
||||
},
|
||||
/* codebook/lsp6.txt */
|
||||
{
|
||||
1,
|
||||
4,
|
||||
16,
|
||||
codes05
|
||||
},
|
||||
/* codebook/lsp7.txt */
|
||||
{
|
||||
1,
|
||||
4,
|
||||
16,
|
||||
codes06
|
||||
},
|
||||
/* codebook/lsp8.txt */
|
||||
{
|
||||
1,
|
||||
3,
|
||||
8,
|
||||
codes07
|
||||
},
|
||||
/* codebook/lsp9.txt */
|
||||
{
|
||||
1,
|
||||
3,
|
||||
8,
|
||||
codes08
|
||||
},
|
||||
/* codebook/lsp10.txt */
|
||||
{
|
||||
1,
|
||||
2,
|
||||
4,
|
||||
codes09
|
||||
},
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
/* codebook/dlsp1.txt */
|
||||
static float codes10[] =
|
||||
{
|
||||
25,
|
||||
50,
|
||||
75,
|
||||
100,
|
||||
125,
|
||||
150,
|
||||
175,
|
||||
200,
|
||||
225,
|
||||
250,
|
||||
275,
|
||||
300,
|
||||
325,
|
||||
350,
|
||||
375,
|
||||
400,
|
||||
425,
|
||||
450,
|
||||
475,
|
||||
500,
|
||||
525,
|
||||
550,
|
||||
575,
|
||||
600,
|
||||
625,
|
||||
650,
|
||||
675,
|
||||
700,
|
||||
725,
|
||||
750,
|
||||
775,
|
||||
800
|
||||
};
|
||||
/* codebook/dlsp2.txt */
|
||||
static float codes11[] =
|
||||
{
|
||||
25,
|
||||
50,
|
||||
75,
|
||||
100,
|
||||
125,
|
||||
150,
|
||||
175,
|
||||
200,
|
||||
225,
|
||||
250,
|
||||
275,
|
||||
300,
|
||||
325,
|
||||
350,
|
||||
375,
|
||||
400,
|
||||
425,
|
||||
450,
|
||||
475,
|
||||
500,
|
||||
525,
|
||||
550,
|
||||
575,
|
||||
600,
|
||||
625,
|
||||
650,
|
||||
675,
|
||||
700,
|
||||
725,
|
||||
750,
|
||||
775,
|
||||
800
|
||||
};
|
||||
/* codebook/dlsp3.txt */
|
||||
static float codes12[] =
|
||||
{
|
||||
25,
|
||||
50,
|
||||
75,
|
||||
100,
|
||||
125,
|
||||
150,
|
||||
175,
|
||||
200,
|
||||
225,
|
||||
250,
|
||||
275,
|
||||
300,
|
||||
325,
|
||||
350,
|
||||
375,
|
||||
400,
|
||||
425,
|
||||
450,
|
||||
475,
|
||||
500,
|
||||
525,
|
||||
550,
|
||||
575,
|
||||
600,
|
||||
625,
|
||||
650,
|
||||
675,
|
||||
700,
|
||||
725,
|
||||
750,
|
||||
775,
|
||||
800
|
||||
};
|
||||
/* codebook/dlsp4.txt */
|
||||
static float codes13[] =
|
||||
{
|
||||
25,
|
||||
50,
|
||||
75,
|
||||
100,
|
||||
125,
|
||||
150,
|
||||
175,
|
||||
200,
|
||||
250,
|
||||
300,
|
||||
350,
|
||||
400,
|
||||
450,
|
||||
500,
|
||||
550,
|
||||
600,
|
||||
650,
|
||||
700,
|
||||
750,
|
||||
800,
|
||||
850,
|
||||
900,
|
||||
950,
|
||||
1000,
|
||||
1050,
|
||||
1100,
|
||||
1150,
|
||||
1200,
|
||||
1250,
|
||||
1300,
|
||||
1350,
|
||||
1400
|
||||
};
|
||||
/* codebook/dlsp5.txt */
|
||||
static float codes14[] =
|
||||
{
|
||||
25,
|
||||
50,
|
||||
75,
|
||||
100,
|
||||
125,
|
||||
150,
|
||||
175,
|
||||
200,
|
||||
250,
|
||||
300,
|
||||
350,
|
||||
400,
|
||||
450,
|
||||
500,
|
||||
550,
|
||||
600,
|
||||
650,
|
||||
700,
|
||||
750,
|
||||
800,
|
||||
850,
|
||||
900,
|
||||
950,
|
||||
1000,
|
||||
1050,
|
||||
1100,
|
||||
1150,
|
||||
1200,
|
||||
1250,
|
||||
1300,
|
||||
1350,
|
||||
1400
|
||||
};
|
||||
/* codebook/dlsp6.txt */
|
||||
static float codes15[] =
|
||||
{
|
||||
25,
|
||||
50,
|
||||
75,
|
||||
100,
|
||||
125,
|
||||
150,
|
||||
175,
|
||||
200,
|
||||
250,
|
||||
300,
|
||||
350,
|
||||
400,
|
||||
450,
|
||||
500,
|
||||
550,
|
||||
600,
|
||||
650,
|
||||
700,
|
||||
750,
|
||||
800,
|
||||
850,
|
||||
900,
|
||||
950,
|
||||
1000,
|
||||
1050,
|
||||
1100,
|
||||
1150,
|
||||
1200,
|
||||
1250,
|
||||
1300,
|
||||
1350,
|
||||
1400
|
||||
};
|
||||
/* codebook/dlsp7.txt */
|
||||
static float codes16[] =
|
||||
{
|
||||
25,
|
||||
50,
|
||||
75,
|
||||
100,
|
||||
125,
|
||||
150,
|
||||
175,
|
||||
200,
|
||||
225,
|
||||
250,
|
||||
275,
|
||||
300,
|
||||
325,
|
||||
350,
|
||||
375,
|
||||
400,
|
||||
425,
|
||||
450,
|
||||
475,
|
||||
500,
|
||||
525,
|
||||
550,
|
||||
575,
|
||||
600,
|
||||
625,
|
||||
650,
|
||||
675,
|
||||
700,
|
||||
725,
|
||||
750,
|
||||
775,
|
||||
800
|
||||
};
|
||||
/* codebook/dlsp8.txt */
|
||||
static float codes17[] =
|
||||
{
|
||||
25,
|
||||
50,
|
||||
75,
|
||||
100,
|
||||
125,
|
||||
150,
|
||||
175,
|
||||
200,
|
||||
225,
|
||||
250,
|
||||
275,
|
||||
300,
|
||||
325,
|
||||
350,
|
||||
375,
|
||||
400,
|
||||
425,
|
||||
450,
|
||||
475,
|
||||
500,
|
||||
525,
|
||||
550,
|
||||
575,
|
||||
600,
|
||||
625,
|
||||
650,
|
||||
675,
|
||||
700,
|
||||
725,
|
||||
750,
|
||||
775,
|
||||
800
|
||||
};
|
||||
/* codebook/dlsp9.txt */
|
||||
static float codes18[] =
|
||||
{
|
||||
25,
|
||||
50,
|
||||
75,
|
||||
100,
|
||||
125,
|
||||
150,
|
||||
175,
|
||||
200,
|
||||
225,
|
||||
250,
|
||||
275,
|
||||
300,
|
||||
325,
|
||||
350,
|
||||
375,
|
||||
400,
|
||||
425,
|
||||
450,
|
||||
475,
|
||||
500,
|
||||
525,
|
||||
550,
|
||||
575,
|
||||
600,
|
||||
625,
|
||||
650,
|
||||
675,
|
||||
700,
|
||||
725,
|
||||
750,
|
||||
775,
|
||||
800
|
||||
};
|
||||
/* codebook/dlsp10.txt */
|
||||
static float codes19[] =
|
||||
{
|
||||
25,
|
||||
50,
|
||||
75,
|
||||
100,
|
||||
125,
|
||||
150,
|
||||
175,
|
||||
200,
|
||||
225,
|
||||
250,
|
||||
275,
|
||||
300,
|
||||
325,
|
||||
350,
|
||||
375,
|
||||
400,
|
||||
425,
|
||||
450,
|
||||
475,
|
||||
500,
|
||||
525,
|
||||
550,
|
||||
575,
|
||||
600,
|
||||
625,
|
||||
650,
|
||||
675,
|
||||
700,
|
||||
725,
|
||||
750,
|
||||
775,
|
||||
800
|
||||
};
|
||||
|
||||
const struct lsp_codebook lsp_cbd[] =
|
||||
{
|
||||
/* codebook/dlsp1.txt */
|
||||
{
|
||||
1,
|
||||
5,
|
||||
32,
|
||||
codes10
|
||||
},
|
||||
/* codebook/dlsp2.txt */
|
||||
{
|
||||
1,
|
||||
5,
|
||||
32,
|
||||
codes11
|
||||
},
|
||||
/* codebook/dlsp3.txt */
|
||||
{
|
||||
1,
|
||||
5,
|
||||
32,
|
||||
codes12
|
||||
},
|
||||
/* codebook/dlsp4.txt */
|
||||
{
|
||||
1,
|
||||
5,
|
||||
32,
|
||||
codes13
|
||||
},
|
||||
/* codebook/dlsp5.txt */
|
||||
{
|
||||
1,
|
||||
5,
|
||||
32,
|
||||
codes14
|
||||
},
|
||||
/* codebook/dlsp6.txt */
|
||||
{
|
||||
1,
|
||||
5,
|
||||
32,
|
||||
codes15
|
||||
},
|
||||
/* codebook/dlsp7.txt */
|
||||
{
|
||||
1,
|
||||
5,
|
||||
32,
|
||||
codes16
|
||||
},
|
||||
/* codebook/dlsp8.txt */
|
||||
{
|
||||
1,
|
||||
5,
|
||||
32,
|
||||
codes17
|
||||
},
|
||||
/* codebook/dlsp9.txt */
|
||||
{
|
||||
1,
|
||||
5,
|
||||
32,
|
||||
codes18
|
||||
},
|
||||
/* codebook/dlsp10.txt */
|
||||
{
|
||||
1,
|
||||
5,
|
||||
32,
|
||||
codes19
|
||||
},
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
|
||||
/* codebook/gecb.txt */
|
||||
static float codes30[] =
|
||||
{
|
||||
2.71, 12.0184,
|
||||
0.04675, -2.73881,
|
||||
0.120993, 8.38895,
|
||||
-1.58028, -0.892307,
|
||||
1.19307, -1.91561,
|
||||
0.187101, -3.27679,
|
||||
0.332251, -7.66455,
|
||||
-1.47944, 31.2461,
|
||||
1.52761, 27.7095,
|
||||
-0.524379, 5.25012,
|
||||
0.55333, 7.4388,
|
||||
-0.843451, -1.95299,
|
||||
2.26389, 8.61029,
|
||||
0.143143, 2.36549,
|
||||
0.616506, 1.28427,
|
||||
-1.71133, 22.0967,
|
||||
1.00813, 17.3965,
|
||||
-0.106718, 1.41891,
|
||||
-0.136246, 14.2736,
|
||||
-1.70909, -20.5319,
|
||||
1.65787, -3.39107,
|
||||
0.138049, -4.95785,
|
||||
0.536729, -1.94375,
|
||||
0.196307, 36.8519,
|
||||
1.27248, 22.5565,
|
||||
-0.670219, -1.90604,
|
||||
0.382092, 6.40113,
|
||||
-0.756911, -4.90102,
|
||||
1.82931, 4.6138,
|
||||
0.318794, 0.73683,
|
||||
0.612815, -2.07505,
|
||||
-0.410151, 24.7871,
|
||||
1.77602, 13.1909,
|
||||
0.106457, -0.104492,
|
||||
0.192206, 10.1838,
|
||||
-1.82442, -7.71565,
|
||||
0.931346, 4.34835,
|
||||
0.308813, -4.086,
|
||||
0.397143, -11.8089,
|
||||
-0.048715, 41.2273,
|
||||
0.877342, 35.8503,
|
||||
-0.759794, 0.476634,
|
||||
0.978593, 7.67467,
|
||||
-1.19506, 3.03883,
|
||||
2.63989, -3.41106,
|
||||
0.191127, 3.60351,
|
||||
0.402932, 1.0843,
|
||||
-2.15202, 18.1076,
|
||||
1.5468, 8.32271,
|
||||
-0.143089, -4.07592,
|
||||
-0.150142, 5.86674,
|
||||
-1.40844, -3.2507,
|
||||
1.56615, -10.4132,
|
||||
0.178171, -10.2267,
|
||||
0.362164, -0.028556,
|
||||
-0.070125, 24.3907,
|
||||
0.594752, 17.4828,
|
||||
-0.28698, -6.90407,
|
||||
0.464818, 10.2055,
|
||||
-1.00684, -14.3572,
|
||||
2.32957, -3.69161,
|
||||
0.335745, 2.40714,
|
||||
1.01966, -3.15565,
|
||||
-1.25945, 7.9919,
|
||||
2.38369, 19.6806,
|
||||
-0.094947, -2.41374,
|
||||
0.20933, 6.66477,
|
||||
-2.22103, 1.37986,
|
||||
1.29239, 2.04633,
|
||||
0.243626, -0.890741,
|
||||
0.428773, -7.19366,
|
||||
-1.11374, 41.3414,
|
||||
2.6098, 31.1405,
|
||||
-0.446468, 2.53419,
|
||||
0.490104, 4.62757,
|
||||
-1.11723, -3.24174,
|
||||
1.79156, 8.41493,
|
||||
0.156012, 0.183336,
|
||||
0.532447, 3.15455,
|
||||
-0.764484, 18.514,
|
||||
0.952395, 11.7713,
|
||||
-0.332567, 0.346987,
|
||||
0.202165, 14.7168,
|
||||
-2.12924, -15.559,
|
||||
1.35358, -1.92679,
|
||||
-0.010963, -16.3364,
|
||||
0.399053, -2.79057,
|
||||
0.750657, 31.1483,
|
||||
0.655743, 24.4819,
|
||||
-0.45321, -0.735879,
|
||||
0.2869, 6.5467,
|
||||
-0.715673, -12.3578,
|
||||
1.54849, 3.87217,
|
||||
0.271874, 0.802339,
|
||||
0.502073, -4.85485,
|
||||
-0.497037, 17.7619,
|
||||
1.19116, 13.9544,
|
||||
0.01563, 1.33157,
|
||||
0.341867, 8.93537,
|
||||
-2.31601, -5.39506,
|
||||
0.75861, 1.9645,
|
||||
0.24132, -3.23769,
|
||||
0.267151, -11.2344,
|
||||
-0.273126, 32.6248,
|
||||
1.75352, 40.432,
|
||||
-0.784011, 3.04576,
|
||||
0.705987, 5.66118,
|
||||
-1.3864, 1.35356,
|
||||
2.37646, 1.67485,
|
||||
0.242973, 4.73218,
|
||||
0.491227, 0.354061,
|
||||
-1.60676, 8.65895,
|
||||
1.16711, 5.9871,
|
||||
-0.137601, -12.0417,
|
||||
-0.251375, 10.3972,
|
||||
-1.43151, -8.90411,
|
||||
0.98828, -13.209,
|
||||
0.261484, -6.35497,
|
||||
0.395932, -0.702529,
|
||||
0.283704, 26.8996,
|
||||
0.420959, 15.4418,
|
||||
-0.355804, -13.7278,
|
||||
0.527372, 12.3985,
|
||||
-1.16956, -15.9985,
|
||||
1.90669, -5.81605,
|
||||
0.354492, 3.85157,
|
||||
0.82576, -4.16264,
|
||||
-0.49019, 13.0572,
|
||||
2.25577, 13.5264,
|
||||
-0.004956, -3.23713,
|
||||
0.026709, 7.86645,
|
||||
-1.81037, -0.451183,
|
||||
1.08383, -0.18362,
|
||||
0.135836, -2.26658,
|
||||
0.375812, -5.51225,
|
||||
-1.96644, 38.6829,
|
||||
1.97799, 24.5655,
|
||||
-0.704656, 6.35881,
|
||||
0.480786, 7.05175,
|
||||
-0.976417, -2.42273,
|
||||
2.50215, 6.75935,
|
||||
0.083588, 3.2588,
|
||||
0.543629, 0.910013,
|
||||
-1.23196, 23.0915,
|
||||
0.785492, 14.807,
|
||||
-0.213554, 1.688,
|
||||
0.004748, 18.1718,
|
||||
-1.54719, -16.1168,
|
||||
1.50104, -3.28114,
|
||||
0.080133, -4.63472,
|
||||
0.476592, -2.18093,
|
||||
0.44247, 40.304,
|
||||
1.07277, 27.592,
|
||||
-0.594738, -4.16681,
|
||||
0.42248, 7.61609,
|
||||
-0.927521, -7.27441,
|
||||
1.99162, 1.29636,
|
||||
0.291307, 2.39878,
|
||||
0.721081, -1.95062,
|
||||
-0.804256, 24.9295,
|
||||
1.64839, 19.1197,
|
||||
0.060852, -0.590639,
|
||||
0.266085, 9.10325,
|
||||
-1.9574, -2.88461,
|
||||
1.11693, 2.6724,
|
||||
0.35458, -2.74854,
|
||||
0.330733, -14.1561,
|
||||
-0.527851, 39.5756,
|
||||
0.991152, 43.195,
|
||||
-0.589619, 1.26919,
|
||||
0.787401, 8.73071,
|
||||
-1.0138, 1.02507,
|
||||
2.8254, 1.89538,
|
||||
0.24089, 2.74557,
|
||||
0.427195, 2.54446,
|
||||
-1.95311, 12.244,
|
||||
1.44862, 12.0607,
|
||||
-0.210492, -3.37906,
|
||||
-0.056713, 10.204,
|
||||
-1.65237, -5.10274,
|
||||
1.29475, -12.2708,
|
||||
0.111608, -8.67592,
|
||||
0.326634, -1.16763,
|
||||
0.021781, 31.1258,
|
||||
0.455335, 21.4684,
|
||||
-0.37544, -3.37121,
|
||||
0.39362, 11.302,
|
||||
-0.851456, -19.4149,
|
||||
2.10703, -2.22886,
|
||||
0.373233, 1.92406,
|
||||
0.884438, -1.72058,
|
||||
-0.975127, 9.84013,
|
||||
2.0033, 17.3954,
|
||||
-0.036915, -1.11137,
|
||||
0.148456, 5.39997,
|
||||
-1.91441, 4.77382,
|
||||
1.44791, 0.537122,
|
||||
0.194979, -1.03818,
|
||||
0.495771, -9.95502,
|
||||
-1.05899, 32.9471,
|
||||
2.01122, 32.4544,
|
||||
-0.30965, 4.71911,
|
||||
0.436082, 4.63552,
|
||||
-1.23711, -1.25428,
|
||||
2.02274, 9.42834,
|
||||
0.190342, 1.46077,
|
||||
0.479017, 2.48479,
|
||||
-1.07848, 16.2217,
|
||||
1.20764, 9.65421,
|
||||
-0.258087, -1.67236,
|
||||
0.071852, 13.416,
|
||||
-1.87723, -16.072,
|
||||
1.28957, -4.87118,
|
||||
0.067713, -13.4427,
|
||||
0.435551, -4.1655,
|
||||
0.46614, 30.5895,
|
||||
0.904895, 21.598,
|
||||
-0.518369, -2.53205,
|
||||
0.337363, 5.63726,
|
||||
-0.554975, -17.4005,
|
||||
1.69188, 1.14574,
|
||||
0.227934, 0.889297,
|
||||
0.587303, -5.72973,
|
||||
-0.262133, 18.6666,
|
||||
1.39505, 17.0029,
|
||||
-0.01909, 4.30838,
|
||||
0.304235, 12.6699,
|
||||
-2.07406, -6.46084,
|
||||
0.920546, 1.21296,
|
||||
0.284927, -1.78547,
|
||||
0.209724, -16.024,
|
||||
-0.636067, 31.5768,
|
||||
1.34989, 34.6775,
|
||||
-0.971625, 5.30086,
|
||||
0.590249, 4.44971,
|
||||
-1.56787, 3.60239,
|
||||
2.1455, 4.51666,
|
||||
0.296022, 4.12017,
|
||||
0.445299, 0.868772,
|
||||
-1.44193, 14.1284,
|
||||
1.35575, 6.0074,
|
||||
-0.012814, -7.49657,
|
||||
-0.43, 8.50012,
|
||||
-1.20469, -7.11326,
|
||||
1.10102, -6.83682,
|
||||
0.196463, -6.234,
|
||||
0.436747, -1.12979,
|
||||
0.141052, 22.8549,
|
||||
0.290821, 18.8114,
|
||||
-0.529536, -7.73251,
|
||||
0.63428, 10.7898,
|
||||
-1.33472, -20.3258,
|
||||
1.81564, -1.90332,
|
||||
0.394778, 3.79758,
|
||||
0.732682, -8.18382,
|
||||
-0.741244, 11.7683
|
||||
};
|
||||
|
||||
const struct lsp_codebook ge_cb[] =
|
||||
{
|
||||
/* codebook/gecb.txt */
|
||||
{
|
||||
2,
|
||||
8,
|
||||
256,
|
||||
codes30
|
||||
},
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,100 @@
|
|||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FILE........: codec2.h
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 21 August 2010
|
||||
|
||||
Codec 2 fully quantised encoder and decoder functions. If you want use
|
||||
Codec 2, these are the functions you need to call.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
Copyright (C) 2010 David Rowe
|
||||
|
||||
All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License version 2.1, as
|
||||
published by the Free Software Foundation. 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 Lesser General Public License
|
||||
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __CODEC2__
|
||||
#define __CODEC2__
|
||||
|
||||
#include <complex>
|
||||
|
||||
#include "codec2_internal.h"
|
||||
#include "defines.h"
|
||||
#include "kiss_fft.h"
|
||||
#include "nlp.h"
|
||||
#include "quantise.h"
|
||||
|
||||
#define CODEC2_MODE_3200 0
|
||||
#define CODEC2_MODE_1600 2
|
||||
|
||||
#ifndef CODEC2_MODE_EN_DEFAULT
|
||||
#define CODEC2_MODE_EN_DEFAULT 1
|
||||
#endif
|
||||
|
||||
#define CODEC2_RAND_MAX 32767
|
||||
|
||||
class CCodec2
|
||||
{
|
||||
public:
|
||||
CCodec2(bool is_3200);
|
||||
~CCodec2();
|
||||
void codec2_encode(unsigned char *bits, const short *speech_in);
|
||||
void codec2_decode(short *speech_out, const unsigned char *bits);
|
||||
void codec2_set_mode(bool);
|
||||
bool codec2_get_mode() {return (c2.mode == 3200); };
|
||||
int codec2_samples_per_frame();
|
||||
int codec2_bits_per_frame();
|
||||
|
||||
private:
|
||||
// merged from other files
|
||||
void sample_phase(MODEL *model, std::complex<float> filter_phase[], std::complex<float> A[]);
|
||||
void phase_synth_zero_order(int n_samp, MODEL *model, float *ex_phase, std::complex<float> filter_phase[]);
|
||||
void postfilter(MODEL *model, float *bg_est);
|
||||
|
||||
C2CONST c2const_create(int Fs, float framelength_ms);
|
||||
|
||||
void make_analysis_window(C2CONST *c2const, FFT_STATE *fft_fwd_cfg, float w[], float W[]);
|
||||
void dft_speech(C2CONST *c2const, FFT_STATE &fft_fwd_cfg, std::complex<float> Sw[], float Sn[], float w[]);
|
||||
void two_stage_pitch_refinement(C2CONST *c2const, MODEL *model, std::complex<float> Sw[]);
|
||||
void estimate_amplitudes(MODEL *model, std::complex<float> Sw[], int est_phase);
|
||||
float est_voicing_mbe(C2CONST *c2const, MODEL *model, std::complex<float> Sw[], float W[]);
|
||||
void make_synthesis_window(C2CONST *c2const, float Pn[]);
|
||||
void synthesise(int n_samp, FFTR_STATE *fftr_inv_cfg, float Sn_[], MODEL *model, float Pn[], int shift);
|
||||
int codec2_rand(void);
|
||||
void hs_pitch_refinement(MODEL *model, std::complex<float> Sw[], float pmin, float pmax, float pstep);
|
||||
|
||||
void interp_Wo(MODEL *interp, MODEL *prev, MODEL *next, float Wo_min);
|
||||
void interp_Wo2(MODEL *interp, MODEL *prev, MODEL *next, float weight, float Wo_min);
|
||||
float interp_energy(float prev, float next);
|
||||
void interpolate_lsp_ver2(float interp[], float prev[], float next[], float weight, int order);
|
||||
|
||||
void analyse_one_frame(MODEL *model, const short *speech);
|
||||
void synthesise_one_frame(short speech[], MODEL *model, std::complex<float> Aw[], float gain);
|
||||
void codec2_encode_3200(unsigned char *bits, const short *speech);
|
||||
void codec2_encode_1600(unsigned char *bits, const short *speech);
|
||||
void codec2_decode_3200(short *speech, const unsigned char *bits);
|
||||
void codec2_decode_1600(short *speech, const unsigned char *bits);
|
||||
void ear_protection(float in_out[], int n);
|
||||
void lsp_to_lpc(float *freq, float *ak, int lpcrdr);
|
||||
|
||||
void (CCodec2::*encode)(unsigned char *bits, const short *speech);
|
||||
void (CCodec2::*decode)(short *speech, const unsigned char *bits);
|
||||
Cnlp nlp;
|
||||
CQuantize qt;
|
||||
CODEC2 c2;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,67 @@
|
|||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FILE........: codec2_internal.h
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: April 16 2012
|
||||
|
||||
Header file for Codec2 internal states, exposed via this header
|
||||
file to assist in testing.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
Copyright (C) 2012 David Rowe
|
||||
|
||||
All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License version 2.1, as
|
||||
published by the Free Software Foundation. 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 Lesser General Public License
|
||||
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __CODEC2_INTERNAL__
|
||||
#define __CODEC2_INTERNAL__
|
||||
|
||||
#include "kiss_fft.h"
|
||||
|
||||
using CODEC2 = struct codec2_tag {
|
||||
int mode;
|
||||
int Fs;
|
||||
int n_samp;
|
||||
int m_pitch;
|
||||
int gray; /* non-zero for gray encoding */
|
||||
int lpc_pf; /* LPC post filter on */
|
||||
int bass_boost; /* LPC post filter bass boost */
|
||||
int smoothing; /* enable smoothing for channels with errors */
|
||||
float ex_phase; /* excitation model phase track */
|
||||
float bg_est; /* background noise estimate for post filter */
|
||||
float prev_f0_enc; /* previous frame's f0 estimate */
|
||||
float prev_e_dec; /* previous frame's LPC energy */
|
||||
float beta; /* LPC post filter parameters */
|
||||
float gamma;
|
||||
float xq_enc[2]; /* joint pitch and energy VQ states */
|
||||
float xq_dec[2];
|
||||
float W[FFT_ENC]; /* DFT of w[] */
|
||||
float hpf_states[2]; /* high pass filter states */
|
||||
float prev_lsps_dec[LPC_ORD]; /* previous frame's LSPs */
|
||||
float *softdec; /* optional soft decn bits from demod */
|
||||
MODEL prev_model_dec; /* previous frame's model parameters */
|
||||
C2CONST c2const;
|
||||
FFT_STATE fft_fwd_cfg; /* forward FFT config */
|
||||
FFTR_STATE fftr_fwd_cfg; /* forward real FFT config */
|
||||
FFTR_STATE fftr_inv_cfg; /* inverse FFT config */
|
||||
std::vector<float> w; /* [m_pitch] time domain hamming window */
|
||||
std::vector<float> Pn; /* [2*n_samp] trapezoidal synthesis window */
|
||||
std::vector<float> Sn; /* [m_pitch] input speech */
|
||||
std::vector<float> Sn_; /* [2*n_samp] synthesised output speech */
|
||||
std::vector<float> bpf_buf; /* buffer for band pass filter */
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,127 @@
|
|||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FILE........: defines.h
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 23/4/93
|
||||
|
||||
Defines and structures used throughout the codec.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
Copyright (C) 2009 David Rowe
|
||||
|
||||
All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License version 2.1, as
|
||||
published by the Free Software Foundation. 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 Lesser General Public License
|
||||
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __DEFINES__
|
||||
#define __DEFINES__
|
||||
|
||||
#include <complex>
|
||||
#include <vector>
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
DEFINES
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
/* General defines */
|
||||
|
||||
#define N_S 0.01 /* internal proc frame length in secs */
|
||||
#define TW_S 0.005 /* trapezoidal synth window overlap */
|
||||
#define MAX_AMP 160 /* maximum number of harmonics */
|
||||
#ifndef PI
|
||||
#define PI 3.141592654 /* mathematical constant */
|
||||
#endif
|
||||
#define TWO_PI 6.283185307 /* mathematical constant */
|
||||
#define MAX_STR 2048 /* maximum string size */
|
||||
|
||||
#define FFT_ENC 512 /* size of FFT used for encoder */
|
||||
#define FFT_DEC 512 /* size of FFT used in decoder */
|
||||
#define V_THRESH 6.0 /* voicing threshold in dB */
|
||||
#define LPC_ORD 10 /* LPC order */
|
||||
#define LPC_ORD_LOW 6 /* LPC order for lower rates */
|
||||
|
||||
/* Pitch estimation defines */
|
||||
|
||||
#define M_PITCH_S 0.0400 /* pitch analysis window in s */
|
||||
#define P_MIN_S 0.0025 /* minimum pitch period in s */
|
||||
#define P_MAX_S 0.0200 /* maximum pitch period in s */
|
||||
#define MAXFACTORS 32 // e.g. an fft of length 128 has 4 factors
|
||||
// as far as kissfft is concerned 4*4*4*2
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
TYPEDEFS
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
/* Structure to hold constants calculated at run time based on sample rate */
|
||||
|
||||
using C2CONST = struct c2const_tag
|
||||
{
|
||||
int Fs; /* sample rate of this instance */
|
||||
int n_samp; /* number of samples per 10ms frame at Fs */
|
||||
int max_amp; /* maximum number of harmonics */
|
||||
int m_pitch; /* pitch estimation window size in samples */
|
||||
int p_min; /* minimum pitch period in samples */
|
||||
int p_max; /* maximum pitch period in samples */
|
||||
float Wo_min;
|
||||
float Wo_max;
|
||||
int nw; /* analysis window size in samples */
|
||||
int tw; /* trapezoidal synthesis window overlap */
|
||||
};
|
||||
|
||||
/* Structure to hold model parameters for one frame */
|
||||
|
||||
using MODEL = struct model_tag
|
||||
{
|
||||
float Wo; /* fundamental frequency estimate in radians */
|
||||
int L; /* number of harmonics */
|
||||
float A[MAX_AMP+1]; /* amplitiude of each harmonic */
|
||||
float phi[MAX_AMP+1]; /* phase of each harmonic */
|
||||
int voiced; /* non-zero if this frame is voiced */
|
||||
};
|
||||
|
||||
/* describes each codebook */
|
||||
|
||||
struct lsp_codebook
|
||||
{
|
||||
int k; /* dimension of vector */
|
||||
int log2m; /* number of bits in m */
|
||||
int m; /* elements in codebook */
|
||||
float *cb; /* The elements */
|
||||
};
|
||||
|
||||
using FFT_STATE = struct fft_state_tag
|
||||
{
|
||||
int nfft;
|
||||
bool inverse;
|
||||
int factors[2*MAXFACTORS];
|
||||
std::vector<std::complex<float>> twiddles;
|
||||
};
|
||||
|
||||
using FFTR_STATE = struct fftr_state_tag
|
||||
{
|
||||
FFT_STATE substate;
|
||||
std::vector<std::complex<float>> tmpbuf;
|
||||
std::vector<std::complex<float>> super_twiddles;
|
||||
};
|
||||
|
||||
extern const struct lsp_codebook lsp_cb[];
|
||||
extern const struct lsp_codebook lsp_cbd[];
|
||||
extern const struct lsp_codebook ge_cb[];
|
||||
|
||||
#endif
|
|
@ -0,0 +1,435 @@
|
|||
/*
|
||||
Copyright (c) 2003-2010, Mark Borgerding
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
|
||||
#include "defines.h"
|
||||
#include "kiss_fft.h"
|
||||
|
||||
void CKissFFT::kf_bfly2(std::complex<float> *Fout, const size_t fstride, FFT_STATE &st, int m)
|
||||
{
|
||||
std::complex<float> *Fout2;
|
||||
std::complex<float> *tw1 = st.twiddles.data();
|
||||
std::complex<float> t;
|
||||
Fout2 = Fout + m;
|
||||
do
|
||||
{
|
||||
t = *Fout2 * *tw1;
|
||||
tw1 += fstride;
|
||||
*Fout2 = *Fout - t;
|
||||
*Fout += t;
|
||||
++Fout2;
|
||||
++Fout;
|
||||
}
|
||||
while (--m);
|
||||
}
|
||||
|
||||
void CKissFFT::kf_bfly3(std::complex<float> * Fout, const size_t fstride, FFT_STATE &st, int m)
|
||||
{
|
||||
const size_t m2 = 2 * m;
|
||||
std::complex<float> *tw1,*tw2;
|
||||
std::complex<float> scratch[5];
|
||||
std::complex<float> epi3;
|
||||
epi3 = st.twiddles[fstride*m];
|
||||
|
||||
tw1 = tw2 = st.twiddles.data();
|
||||
|
||||
do
|
||||
{
|
||||
scratch[1] = Fout[m] * *tw1;
|
||||
scratch[2] = Fout[m2] * *tw2;
|
||||
|
||||
scratch[3] = scratch[1] + scratch[2];
|
||||
scratch[0] = scratch[1] - scratch[2];
|
||||
tw1 += fstride;
|
||||
tw2 += fstride*2;
|
||||
|
||||
Fout[m] = *Fout - (0.5f * scratch[3]);
|
||||
|
||||
scratch[0] *= epi3.imag();
|
||||
|
||||
*Fout += scratch[3];
|
||||
|
||||
Fout[m2].real(Fout[m].real() + scratch[0].imag());
|
||||
Fout[m2].imag(Fout[m].imag() - scratch[0].real());
|
||||
|
||||
Fout[m].real(Fout[m].real() - scratch[0].imag());
|
||||
Fout[m].imag(Fout[m].imag() + scratch[0].real());
|
||||
|
||||
++Fout;
|
||||
}
|
||||
while(--m);
|
||||
}
|
||||
|
||||
void CKissFFT::kf_bfly4(std::complex<float> *Fout, const size_t fstride, FFT_STATE &st, int m)
|
||||
{
|
||||
std::complex<float> *tw1,*tw2,*tw3;
|
||||
std::complex<float> scratch[6];
|
||||
int k = m;
|
||||
const int m2 = 2 * m;
|
||||
const int m3 = 3 * m;
|
||||
|
||||
|
||||
tw3 = tw2 = tw1 = st.twiddles.data();
|
||||
|
||||
do
|
||||
{
|
||||
scratch[0] = Fout[m] * *tw1;
|
||||
scratch[1] = Fout[m2] * *tw2;
|
||||
scratch[2] = Fout[m3] * *tw3;
|
||||
|
||||
scratch[5] = *Fout - scratch[1];
|
||||
*Fout += scratch[1];
|
||||
scratch[3] = scratch[0] + scratch[2];
|
||||
scratch[4] = scratch[0] - scratch[2];
|
||||
Fout[m2] = *Fout - scratch[3];
|
||||
tw1 += fstride;
|
||||
tw2 += fstride*2;
|
||||
tw3 += fstride*3;
|
||||
*Fout += scratch[3];
|
||||
|
||||
if(st.inverse)
|
||||
{
|
||||
Fout[m].real(scratch[5].real() - scratch[4].imag());
|
||||
Fout[m].imag(scratch[5].imag() + scratch[4].real());
|
||||
Fout[m3].real(scratch[5].real() + scratch[4].imag());
|
||||
Fout[m3].imag(scratch[5].imag() - scratch[4].real());
|
||||
}
|
||||
else
|
||||
{
|
||||
Fout[m].real(scratch[5].real() + scratch[4].imag());
|
||||
Fout[m].imag(scratch[5].imag() - scratch[4].real());
|
||||
Fout[m3].real(scratch[5].real() - scratch[4].imag());
|
||||
Fout[m3].imag(scratch[5].imag() + scratch[4].real());
|
||||
}
|
||||
++Fout;
|
||||
}
|
||||
while(--k);
|
||||
}
|
||||
|
||||
void CKissFFT::kf_bfly5(std::complex<float> * Fout, const size_t fstride, FFT_STATE &st, int m)
|
||||
{
|
||||
std::complex<float> scratch[13];
|
||||
std::complex<float> *twiddles = st.twiddles.data();
|
||||
auto ya = twiddles[fstride*m];
|
||||
auto yb = twiddles[fstride*2*m];
|
||||
|
||||
auto Fout0 = Fout;
|
||||
auto Fout1 = Fout0 + m;
|
||||
auto Fout2 = Fout0 + 2 * m;
|
||||
auto Fout3 = Fout0 + 3 * m;
|
||||
auto Fout4 = Fout0 + 4 * m;
|
||||
|
||||
auto tw = st.twiddles.data();
|
||||
for (int u=0; u<m; ++u)
|
||||
{
|
||||
scratch[0] = *Fout0;
|
||||
|
||||
scratch[1] = *Fout1 * tw[u*fstride];
|
||||
scratch[2] = *Fout2 * tw[2*u*fstride];
|
||||
scratch[3] = *Fout3 * tw[3*u*fstride];
|
||||
scratch[4] = *Fout4 * tw[4*u*fstride];
|
||||
|
||||
scratch[7] = scratch[1] + scratch[4];
|
||||
scratch[10] = scratch[1] - scratch[4];
|
||||
scratch[8] = scratch[2] + scratch[3];
|
||||
scratch[9] = scratch[2] - scratch[3];
|
||||
|
||||
*Fout0 += scratch[7] + scratch[8];
|
||||
|
||||
scratch[5] = scratch[0] + (scratch[7] * ya.real()) + (scratch[8] * yb.real());
|
||||
|
||||
scratch[6].real( (scratch[10].imag() * ya.imag()) + (scratch[9].imag() * yb.imag()));
|
||||
scratch[6].imag(-(scratch[10].real() * ya.imag()) - (scratch[9].real() * yb.imag()));
|
||||
|
||||
*Fout1 = scratch[5] - scratch[6];
|
||||
*Fout4 = scratch[5] + scratch[6];
|
||||
|
||||
scratch[11] = scratch[0] + (scratch[7] * yb.real()) + (scratch[8] * ya.real());
|
||||
scratch[12].real(-(scratch[10].imag() * yb.imag()) + (scratch[9].imag() * ya.imag()));
|
||||
scratch[12].imag( (scratch[10].real() * yb.imag()) - (scratch[9].real() * ya.imag()));
|
||||
|
||||
*Fout2 = scratch[11] + scratch[12];
|
||||
*Fout3 = scratch[11] - scratch[12];
|
||||
|
||||
++Fout0;
|
||||
++Fout1;
|
||||
++Fout2;
|
||||
++Fout3;
|
||||
++Fout4;
|
||||
}
|
||||
}
|
||||
|
||||
/* perform the butterfly for one stage of a mixed radix FFT */
|
||||
void CKissFFT::kf_bfly_generic(std::complex<float> *Fout, const size_t fstride, FFT_STATE &st, int m, int p)
|
||||
{
|
||||
auto twiddles = st.twiddles.data();
|
||||
std::complex<float> t;
|
||||
int Norig = st.nfft;
|
||||
|
||||
std::vector<std::complex<float>> scratch(p);
|
||||
|
||||
for (int u=0; u<m; ++u)
|
||||
{
|
||||
int k = u;
|
||||
for (int q1=0 ; q1<p ; ++q1)
|
||||
{
|
||||
scratch[q1] = Fout[k];
|
||||
k += m;
|
||||
}
|
||||
|
||||
k = u;
|
||||
for (int q1=0 ; q1<p ; ++q1)
|
||||
{
|
||||
int twidx = 0;
|
||||
Fout[k] = scratch[0];
|
||||
for (int q=1; q<p; ++q)
|
||||
{
|
||||
twidx += fstride * k;
|
||||
if (twidx >= Norig) twidx-=Norig;
|
||||
t = scratch[q] * twiddles[twidx];
|
||||
Fout[k] += t;
|
||||
}
|
||||
k += m;
|
||||
}
|
||||
}
|
||||
scratch.clear();
|
||||
}
|
||||
|
||||
void CKissFFT::kf_work(std::complex<float> *Fout, const std::complex<float> *f, const size_t fstride, int in_stride, int *factors, FFT_STATE &st)
|
||||
{
|
||||
auto Fout_beg = Fout;
|
||||
const int p = *factors++; /* the radix */
|
||||
const int m = *factors++; /* stage's fft length/p */
|
||||
const std::complex<float> *Fout_end = Fout + p*m;
|
||||
|
||||
if (m==1)
|
||||
{
|
||||
do
|
||||
{
|
||||
*Fout = *f;
|
||||
f += fstride*in_stride;
|
||||
}
|
||||
while( ++Fout != Fout_end );
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
// recursive call:
|
||||
// DFT of size m*p performed by doing
|
||||
// p instances of smaller DFTs of size m,
|
||||
// each one takes a decimated version of the input
|
||||
kf_work( Fout, f, fstride*p, in_stride, factors, st);
|
||||
f += fstride*in_stride;
|
||||
}
|
||||
while( (Fout += m) != Fout_end );
|
||||
}
|
||||
|
||||
Fout=Fout_beg;
|
||||
|
||||
// recombine the p smaller DFTs
|
||||
switch (p)
|
||||
{
|
||||
case 2:
|
||||
kf_bfly2(Fout,fstride,st,m);
|
||||
break;
|
||||
case 3:
|
||||
kf_bfly3(Fout,fstride,st,m);
|
||||
break;
|
||||
case 4:
|
||||
kf_bfly4(Fout,fstride,st,m);
|
||||
break;
|
||||
case 5:
|
||||
kf_bfly5(Fout,fstride,st,m);
|
||||
break;
|
||||
default:
|
||||
kf_bfly_generic(Fout,fstride,st,m,p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* facbuf is populated by p1,m1,p2,m2, ...
|
||||
where
|
||||
p[i] * m[i] = m[i-1]
|
||||
m0 = n */
|
||||
void CKissFFT::kf_factor(int n,int * facbuf)
|
||||
{
|
||||
int p=4;
|
||||
double floor_sqrt;
|
||||
floor_sqrt = floorf( sqrtf((double)n) );
|
||||
|
||||
/*factor out powers of 4, powers of 2, then any remaining primes */
|
||||
do
|
||||
{
|
||||
while (n % p)
|
||||
{
|
||||
switch (p)
|
||||
{
|
||||
case 4:
|
||||
p = 2;
|
||||
break;
|
||||
case 2:
|
||||
p = 3;
|
||||
break;
|
||||
default:
|
||||
p += 2;
|
||||
break;
|
||||
}
|
||||
if (p > floor_sqrt)
|
||||
p = n; /* no more factors, skip to end */
|
||||
}
|
||||
n /= p;
|
||||
*facbuf++ = p;
|
||||
*facbuf++ = n;
|
||||
}
|
||||
while (n > 1);
|
||||
}
|
||||
|
||||
void CKissFFT::fft_alloc(FFT_STATE &state, const int nfft, bool inverse_fft)
|
||||
{
|
||||
state.twiddles.resize(nfft);
|
||||
|
||||
state.nfft = nfft;
|
||||
state.inverse = inverse_fft;
|
||||
|
||||
for (int i=0; i<nfft; ++i)
|
||||
{
|
||||
const double pi=3.141592653589793238462643383279502884197169399375105820974944;
|
||||
double phase = -2.0 * pi * i / nfft;
|
||||
if (state.inverse)
|
||||
phase *= -1.0;
|
||||
state.twiddles[i] = std::polar(1.0f, float(phase));
|
||||
}
|
||||
|
||||
kf_factor(nfft, state.factors);
|
||||
}
|
||||
|
||||
|
||||
void CKissFFT::fft_stride(FFT_STATE &st, const std::complex<float> *fin, std::complex<float> *fout, int in_stride)
|
||||
{
|
||||
if (fin == fout)
|
||||
{
|
||||
//NOTE: this is not really an in-place FFT algorithm.
|
||||
//It just performs an out-of-place FFT into a temp buffer
|
||||
std::vector<std::complex<float>> tmpbuf(st.nfft);
|
||||
kf_work(tmpbuf.data(), fin, true, in_stride, st.factors, st);
|
||||
memcpy(fout, tmpbuf.data(), sizeof(std::complex<float>)*st.nfft);
|
||||
tmpbuf.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
kf_work(fout, fin, 1, in_stride, st.factors, st);
|
||||
}
|
||||
}
|
||||
|
||||
void CKissFFT::fft(FFT_STATE &cfg, const std::complex<float> *fin, std::complex<float> *fout)
|
||||
{
|
||||
fft_stride(cfg, fin, fout, 1);
|
||||
}
|
||||
|
||||
int CKissFFT::fft_next_fast_size(int n)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
int m = n;
|
||||
while ( (m % 2) == 0 ) m /= 2;
|
||||
while ( (m % 3) == 0 ) m /= 3;
|
||||
while ( (m % 5) == 0 ) m /= 5;
|
||||
if (m <= 1)
|
||||
break; /* n is completely factorable by twos, threes, and fives */
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void CKissFFT::fftr_alloc(FFTR_STATE &st, int nfft, const bool inverse_fft)
|
||||
{
|
||||
nfft >>= 1;
|
||||
|
||||
fft_alloc(st.substate, nfft, inverse_fft);
|
||||
st.tmpbuf.resize(nfft);
|
||||
st.super_twiddles.resize(nfft);
|
||||
|
||||
for (int i=0; i<nfft/2; ++i)
|
||||
{
|
||||
double phase = -3.141592653589793238462643383279502884197169399375105820974944 * (double(i+1) / nfft + .5);
|
||||
if (inverse_fft)
|
||||
phase *= -1.0;
|
||||
st.super_twiddles[i] = std::polar(1.0f, float(phase));
|
||||
}
|
||||
}
|
||||
|
||||
void CKissFFT::fftr(FFTR_STATE &st, const float *timedata, std::complex<float> *freqdata)
|
||||
{
|
||||
assert(st.substate.inverse == false);
|
||||
|
||||
auto ncfft = st.substate.nfft;
|
||||
|
||||
/*perform the parallel fft of two real signals packed in real,imag*/
|
||||
fft( st.substate, (const std::complex<float>*)timedata, st.tmpbuf.data());
|
||||
/* The real part of the DC element of the frequency spectrum in st->tmpbuf
|
||||
* contains the sum of the even-numbered elements of the input time sequence
|
||||
* The imag part is the sum of the odd-numbered elements
|
||||
*
|
||||
* The sum of tdc.r and tdc.i is the sum of the input time sequence.
|
||||
* yielding DC of input time sequence
|
||||
* The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1...
|
||||
* yielding Nyquist bin of input time sequence
|
||||
*/
|
||||
|
||||
auto tdc = st.tmpbuf[0];
|
||||
freqdata[0].real(tdc.real() + tdc.imag());
|
||||
freqdata[ncfft].real(tdc.real() - tdc.imag());
|
||||
freqdata[ncfft].imag(0.f);
|
||||
freqdata[0].imag(0.f);
|
||||
|
||||
for (int k=1; k <= ncfft/2; ++k)
|
||||
{
|
||||
auto fpk = st.tmpbuf[k];
|
||||
auto fpnk = std::conj(st.tmpbuf[ncfft-k]);
|
||||
|
||||
auto f1k = fpk + fpnk;
|
||||
auto f2k = fpk - fpnk;
|
||||
auto tw = f2k * st.super_twiddles[k-1];
|
||||
|
||||
freqdata[k] = 0.5f * (f1k + tw);
|
||||
freqdata[ncfft-k].real(0.5f * (f1k.real() - tw.real()));
|
||||
freqdata[ncfft-k].imag(0.5f * (tw.imag() - f1k.imag()));
|
||||
}
|
||||
}
|
||||
|
||||
void CKissFFT::fftri(FFTR_STATE &st, const std::complex<float> *freqdata, float *timedata)
|
||||
{
|
||||
assert(st.substate.inverse == true);
|
||||
|
||||
auto ncfft = st.substate.nfft;
|
||||
|
||||
st.tmpbuf[0].real(freqdata[0].real() + freqdata[ncfft].real());
|
||||
st.tmpbuf[0].imag(freqdata[0].real() - freqdata[ncfft].real());
|
||||
|
||||
for (int k=1; k <= ncfft/2; ++k)
|
||||
{
|
||||
auto fk = freqdata[k];
|
||||
auto fnkc = std::conj(freqdata[ncfft - k]);
|
||||
|
||||
auto fek = fk + fnkc;
|
||||
auto tmp = fk - fnkc;
|
||||
auto fok = tmp * st.super_twiddles[k-1];
|
||||
st.tmpbuf[k] = fek + fok;
|
||||
st.tmpbuf[ncfft - k] = std::conj(fek - fok);
|
||||
}
|
||||
fft (st.substate, st.tmpbuf.data(), (std::complex<float> *)timedata);
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
#ifndef KISS_FFT_H
|
||||
#define KISS_FFT_H
|
||||
|
||||
#include <complex>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
/* for real ffts, we need an even size */
|
||||
#define kiss_fftr_next_fast_size_real(n) (kiss_fft_next_fast_size( ((n)+1) >> 1) << 1 )
|
||||
|
||||
class CKissFFT
|
||||
{
|
||||
public:
|
||||
void fft_alloc(FFT_STATE &state, const int nfft, const bool inverse_fft);
|
||||
void fft(FFT_STATE &cfg, const std::complex<float> *fin, std::complex<float> *fout);
|
||||
void fft_stride(FFT_STATE &cfg, const std::complex<float> *fin, std::complex<float> *fout, int fin_stride);
|
||||
int fft_next_fast_size(int n);
|
||||
void fftr_alloc(FFTR_STATE &state, int nfft, const bool inverse_fft);
|
||||
void fftr(FFTR_STATE &cfg,const float *timedata,std::complex<float> *freqdata);
|
||||
void fftri(FFTR_STATE &cfg,const std::complex<float> *freqdata,float *timedata);
|
||||
private:
|
||||
void kf_bfly2(std::complex<float> *Fout, const size_t fstride, FFT_STATE &st, int m);
|
||||
void kf_bfly3(std::complex<float> *Fout, const size_t fstride, FFT_STATE &st, int m);
|
||||
void kf_bfly4(std::complex<float> *Fout, const size_t fstride, FFT_STATE &st, int m);
|
||||
void kf_bfly5(std::complex<float> *Fout, const size_t fstride, FFT_STATE &st, int m);
|
||||
void kf_bfly_generic(std::complex<float> *Fout, const size_t fstride, FFT_STATE &st, int m, int p);
|
||||
void kf_work(std::complex<float> *Fout, const std::complex<float> *f, const size_t fstride, int in_stride, int *factors, FFT_STATE &st);
|
||||
void kf_factor(int n, int *facbuf);
|
||||
};
|
||||
#endif
|
|
@ -0,0 +1,311 @@
|
|||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FILE........: lpc.c
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 30 Sep 1990 (!)
|
||||
|
||||
Linear Prediction functions written in C.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
Copyright (C) 2009-2012 David Rowe
|
||||
|
||||
All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License version 2.1, as
|
||||
published by the Free Software Foundation. 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 Lesser General Public License
|
||||
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define LPC_MAX_N 512 /* maximum no. of samples in frame */
|
||||
#define PI 3.141592654 /* mathematical constant */
|
||||
|
||||
#define ALPHA 1.0
|
||||
#define BETA 0.94
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include "defines.h"
|
||||
#include "lpc.h"
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
pre_emp()
|
||||
|
||||
Pre-emphasise (high pass filter with zero close to 0 Hz) a frame of
|
||||
speech samples. Helps reduce dynamic range of LPC spectrum, giving
|
||||
greater weight and hense a better match to low energy formants.
|
||||
|
||||
Should be balanced by de-emphasis of the output speech.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void Clpc::pre_emp(
|
||||
float Sn_pre[], /* output frame of speech samples */
|
||||
float Sn[], /* input frame of speech samples */
|
||||
float *mem, /* Sn[-1]single sample memory */
|
||||
int Nsam /* number of speech samples to use */
|
||||
)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i<Nsam; i++)
|
||||
{
|
||||
Sn_pre[i] = Sn[i] - ALPHA * mem[0];
|
||||
mem[0] = Sn[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
de_emp()
|
||||
|
||||
De-emphasis filter (low pass filter with a pole close to 0 Hz).
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void Clpc::de_emp(
|
||||
float Sn_de[], /* output frame of speech samples */
|
||||
float Sn[], /* input frame of speech samples */
|
||||
float *mem, /* Sn[-1]single sample memory */
|
||||
int Nsam /* number of speech samples to use */
|
||||
)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; i<Nsam; i++)
|
||||
{
|
||||
Sn_de[i] = Sn[i] + BETA * mem[0];
|
||||
mem[0] = Sn_de[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
hanning_window()
|
||||
|
||||
Hanning windows a frame of speech samples.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void Clpc::hanning_window(
|
||||
float Sn[], /* input frame of speech samples */
|
||||
float Wn[], /* output frame of windowed samples */
|
||||
int Nsam /* number of samples */
|
||||
)
|
||||
{
|
||||
int i; /* loop variable */
|
||||
|
||||
for(i=0; i<Nsam; i++)
|
||||
Wn[i] = Sn[i]*(0.5 - 0.5*cosf(2*PI*(float)i/(Nsam-1)));
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
autocorrelate()
|
||||
|
||||
Finds the first P autocorrelation values of an array of windowed speech
|
||||
samples Sn[].
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void Clpc::autocorrelate(
|
||||
float Sn[], /* frame of Nsam windowed speech samples */
|
||||
float Rn[], /* array of P+1 autocorrelation coefficients */
|
||||
int Nsam, /* number of windowed samples to use */
|
||||
int order /* order of LPC analysis */
|
||||
)
|
||||
{
|
||||
int i,j; /* loop variables */
|
||||
|
||||
for(j=0; j<order+1; j++)
|
||||
{
|
||||
Rn[j] = 0.0;
|
||||
for(i=0; i<Nsam-j; i++)
|
||||
Rn[j] += Sn[i]*Sn[i+j];
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
levinson_durbin()
|
||||
|
||||
Given P+1 autocorrelation coefficients, finds P Linear Prediction Coeff.
|
||||
(LPCs) where P is the order of the LPC all-pole model. The Levinson-Durbin
|
||||
algorithm is used, and is described in:
|
||||
|
||||
J. Makhoul
|
||||
"Linear prediction, a tutorial review"
|
||||
Proceedings of the IEEE
|
||||
Vol-63, No. 4, April 1975
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void Clpc::levinson_durbin(
|
||||
float R[], /* order+1 autocorrelation coeff */
|
||||
float lpcs[], /* order+1 LPC's */
|
||||
int order /* order of the LPC analysis */
|
||||
)
|
||||
{
|
||||
float a[order+1][order+1];
|
||||
float sum, e, k;
|
||||
int i,j; /* loop variables */
|
||||
|
||||
e = R[0]; /* Equation 38a, Makhoul */
|
||||
|
||||
for(i=1; i<=order; i++)
|
||||
{
|
||||
sum = 0.0;
|
||||
for(j=1; j<=i-1; j++)
|
||||
sum += a[i-1][j]*R[i-j];
|
||||
k = -1.0*(R[i] + sum)/e; /* Equation 38b, Makhoul */
|
||||
if (fabsf(k) > 1.0)
|
||||
k = 0.0;
|
||||
|
||||
a[i][i] = k;
|
||||
|
||||
for(j=1; j<=i-1; j++)
|
||||
a[i][j] = a[i-1][j] + k*a[i-1][i-j]; /* Equation 38c, Makhoul */
|
||||
|
||||
e *= (1-k*k); /* Equation 38d, Makhoul */
|
||||
}
|
||||
|
||||
for(i=1; i<=order; i++)
|
||||
lpcs[i] = a[order][i];
|
||||
lpcs[0] = 1.0;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
inverse_filter()
|
||||
|
||||
Inverse Filter, A(z). Produces an array of residual samples from an array
|
||||
of input samples and linear prediction coefficients.
|
||||
|
||||
The filter memory is stored in the first order samples of the input array.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void Clpc::inverse_filter(
|
||||
float Sn[], /* Nsam input samples */
|
||||
float a[], /* LPCs for this frame of samples */
|
||||
int Nsam, /* number of samples */
|
||||
float res[], /* Nsam residual samples */
|
||||
int order /* order of LPC */
|
||||
)
|
||||
{
|
||||
int i,j; /* loop variables */
|
||||
|
||||
for(i=0; i<Nsam; i++)
|
||||
{
|
||||
res[i] = 0.0;
|
||||
for(j=0; j<=order; j++)
|
||||
res[i] += Sn[i-j]*a[j];
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
synthesis_filter()
|
||||
|
||||
C version of the Speech Synthesis Filter, 1/A(z). Given an array of
|
||||
residual or excitation samples, and the the LP filter coefficients, this
|
||||
function will produce an array of speech samples. This filter structure is
|
||||
IIR.
|
||||
|
||||
The synthesis filter has memory as well, this is treated in the same way
|
||||
as the memory for the inverse filter (see inverse_filter() notes above).
|
||||
The difference is that the memory for the synthesis filter is stored in
|
||||
the output array, wheras the memory of the inverse filter is stored in the
|
||||
input array.
|
||||
|
||||
Note: the calling function must update the filter memory.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void Clpc::synthesis_filter(
|
||||
float res[], /* Nsam input residual (excitation) samples */
|
||||
float a[], /* LPCs for this frame of speech samples */
|
||||
int Nsam, /* number of speech samples */
|
||||
int order, /* LPC order */
|
||||
float Sn_[] /* Nsam output synthesised speech samples */
|
||||
)
|
||||
{
|
||||
int i,j; /* loop variables */
|
||||
|
||||
/* Filter Nsam samples */
|
||||
|
||||
for(i=0; i<Nsam; i++)
|
||||
{
|
||||
Sn_[i] = res[i]*a[0];
|
||||
for(j=1; j<=order; j++)
|
||||
Sn_[i] -= Sn_[i-j]*a[j];
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
find_aks()
|
||||
|
||||
This function takes a frame of samples, and determines the linear
|
||||
prediction coefficients for that frame of samples.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void Clpc::find_aks(
|
||||
float Sn[], /* Nsam samples with order sample memory */
|
||||
float a[], /* order+1 LPCs with first coeff 1.0 */
|
||||
int Nsam, /* number of input speech samples */
|
||||
int order, /* order of the LPC analysis */
|
||||
float *E /* residual energy */
|
||||
)
|
||||
{
|
||||
float Wn[LPC_MAX_N]; /* windowed frame of Nsam speech samples */
|
||||
float R[order+1]; /* order+1 autocorrelation values of Sn[] */
|
||||
int i;
|
||||
|
||||
assert(Nsam < LPC_MAX_N);
|
||||
|
||||
hanning_window(Sn,Wn,Nsam);
|
||||
autocorrelate(Wn,R,Nsam,order);
|
||||
levinson_durbin(R,a,order);
|
||||
|
||||
*E = 0.0;
|
||||
for(i=0; i<=order; i++)
|
||||
*E += a[i]*R[i];
|
||||
if (*E < 0.0)
|
||||
*E = 1E-12;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
weight()
|
||||
|
||||
Weights a vector of LPCs.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void Clpc::weight(
|
||||
float ak[], /* vector of order+1 LPCs */
|
||||
float gamma, /* weighting factor */
|
||||
int order, /* num LPCs (excluding leading 1.0) */
|
||||
float akw[] /* weighted vector of order+1 LPCs */
|
||||
)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=1; i<=order; i++)
|
||||
akw[i] = ak[i]*powf(gamma,(float)i);
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FILE........: lpc.h
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 24/8/09
|
||||
|
||||
Linear Prediction functions written in C.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
Copyright (C) 2009-2012 David Rowe
|
||||
|
||||
All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License version 2.1, as
|
||||
published by the Free Software Foundation. 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 Lesser General Public License
|
||||
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __LPC__
|
||||
#define __LPC__
|
||||
|
||||
#define LPC_MAX_ORDER 20
|
||||
|
||||
class Clpc {
|
||||
public:
|
||||
void autocorrelate(float Sn[], float Rn[], int Nsam, int order);
|
||||
void levinson_durbin(float R[], float lpcs[], int order);
|
||||
private:
|
||||
void pre_emp(float Sn_pre[], float Sn[], float *mem, int Nsam);
|
||||
void de_emp(float Sn_se[], float Sn[], float *mem, int Nsam);
|
||||
void hanning_window(float Sn[], float Wn[], int Nsam);
|
||||
void inverse_filter(float Sn[], float a[], int Nsam, float res[], int order);
|
||||
void synthesis_filter(float res[], float a[], int Nsam, int order, float Sn_[]);
|
||||
void find_aks(float Sn[], float a[], int Nsam, int order, float *E);
|
||||
void weight(float ak[], float gamma, int order, float akw[]);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,520 @@
|
|||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FILE........: nlp.c
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 23/3/93
|
||||
|
||||
Non Linear Pitch (NLP) estimation functions.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
Copyright (C) 2009 David Rowe
|
||||
|
||||
All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License version 2.1, as
|
||||
published by the Free Software Foundation. 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 Lesser General Public License
|
||||
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "defines.h"
|
||||
#include "nlp.h"
|
||||
#include "kiss_fft.h"
|
||||
|
||||
extern CKissFFT kiss;
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
GLOBALS
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
/* 48 tap 600Hz low pass FIR filter coefficients */
|
||||
|
||||
static const float nlp_fir[] =
|
||||
{
|
||||
-1.0818124e-03,
|
||||
-1.1008344e-03,
|
||||
-9.2768838e-04,
|
||||
-4.2289438e-04,
|
||||
5.5034190e-04,
|
||||
2.0029849e-03,
|
||||
3.7058509e-03,
|
||||
5.1449415e-03,
|
||||
5.5924666e-03,
|
||||
4.3036754e-03,
|
||||
8.0284511e-04,
|
||||
-4.8204610e-03,
|
||||
-1.1705810e-02,
|
||||
-1.8199275e-02,
|
||||
-2.2065282e-02,
|
||||
-2.0920610e-02,
|
||||
-1.2808831e-02,
|
||||
3.2204775e-03,
|
||||
2.6683811e-02,
|
||||
5.5520624e-02,
|
||||
8.6305944e-02,
|
||||
1.1480192e-01,
|
||||
1.3674206e-01,
|
||||
1.4867556e-01,
|
||||
1.4867556e-01,
|
||||
1.3674206e-01,
|
||||
1.1480192e-01,
|
||||
8.6305944e-02,
|
||||
5.5520624e-02,
|
||||
2.6683811e-02,
|
||||
3.2204775e-03,
|
||||
-1.2808831e-02,
|
||||
-2.0920610e-02,
|
||||
-2.2065282e-02,
|
||||
-1.8199275e-02,
|
||||
-1.1705810e-02,
|
||||
-4.8204610e-03,
|
||||
8.0284511e-04,
|
||||
4.3036754e-03,
|
||||
5.5924666e-03,
|
||||
5.1449415e-03,
|
||||
3.7058509e-03,
|
||||
2.0029849e-03,
|
||||
5.5034190e-04,
|
||||
-4.2289438e-04,
|
||||
-9.2768838e-04,
|
||||
-1.1008344e-03,
|
||||
-1.0818124e-03
|
||||
};
|
||||
|
||||
static const float fdmdv_os_filter[]= {
|
||||
-0.0008215855034550382,
|
||||
-0.0007833023901802921,
|
||||
0.001075563790768233,
|
||||
0.001199092367787555,
|
||||
-0.001765309502928316,
|
||||
-0.002055372115328064,
|
||||
0.002986877604154257,
|
||||
0.003462567920638414,
|
||||
-0.004856570111126334,
|
||||
-0.005563143845031497,
|
||||
0.007533613299748122,
|
||||
0.008563932468880897,
|
||||
-0.01126857129039911,
|
||||
-0.01280782411693687,
|
||||
0.01651443896361847,
|
||||
0.01894875110322284,
|
||||
-0.02421604439474981,
|
||||
-0.02845107338464062,
|
||||
0.03672973563400258,
|
||||
0.04542046150312214,
|
||||
-0.06189165826716491,
|
||||
-0.08721876380763803,
|
||||
0.1496157094199961,
|
||||
0.4497962274137046,
|
||||
0.4497962274137046,
|
||||
0.1496157094199961,
|
||||
-0.08721876380763803,
|
||||
-0.0618916582671649,
|
||||
0.04542046150312216,
|
||||
0.03672973563400257,
|
||||
-0.02845107338464062,
|
||||
-0.02421604439474984,
|
||||
0.01894875110322284,
|
||||
0.01651443896361848,
|
||||
-0.01280782411693687,
|
||||
-0.0112685712903991,
|
||||
0.008563932468880899,
|
||||
0.007533613299748123,
|
||||
-0.005563143845031501,
|
||||
-0.004856570111126346,
|
||||
0.003462567920638419,
|
||||
0.002986877604154259,
|
||||
-0.002055372115328063,
|
||||
-0.001765309502928318,
|
||||
0.001199092367787557,
|
||||
0.001075563790768233,
|
||||
-0.0007833023901802925,
|
||||
-0.0008215855034550383
|
||||
};
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
nlp_create()
|
||||
|
||||
Initialisation function for NLP pitch estimator.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void Cnlp::nlp_create(C2CONST *c2const)
|
||||
{
|
||||
int i;
|
||||
int m = c2const->m_pitch;
|
||||
int Fs = c2const->Fs;
|
||||
|
||||
assert((Fs == 8000) || (Fs == 16000));
|
||||
snlp.Fs = Fs;
|
||||
|
||||
snlp.m = m;
|
||||
|
||||
/* if running at 16kHz allocate storage for decimating filter memory */
|
||||
|
||||
if (Fs == 16000)
|
||||
{
|
||||
snlp.Sn16k.resize(FDMDV_OS_TAPS_16K + c2const->n_samp);
|
||||
for(i=0; i<FDMDV_OS_TAPS_16K; i++)
|
||||
{
|
||||
snlp.Sn16k[i] = 0.0;
|
||||
}
|
||||
|
||||
/* most processing occurs at 8 kHz sample rate so halve m */
|
||||
|
||||
m /= 2;
|
||||
}
|
||||
|
||||
assert(m <= PMAX_M);
|
||||
|
||||
for(i=0; i<m/DEC; i++)
|
||||
{
|
||||
snlp.w[i] = 0.5 - 0.5*cosf(2*PI*i/(m/DEC-1));
|
||||
}
|
||||
|
||||
for(i=0; i<PMAX_M; i++)
|
||||
snlp.sq[i] = 0.0;
|
||||
snlp.mem_x = 0.0;
|
||||
snlp.mem_y = 0.0;
|
||||
for(i=0; i<NLP_NTAP; i++)
|
||||
snlp.mem_fir[i] = 0.0;
|
||||
|
||||
kiss.fft_alloc(snlp.fft_cfg, PE_FFT_SIZE, false);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
nlp_destroy()
|
||||
|
||||
Shut down function for NLP pitch estimator.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void Cnlp::nlp_destroy()
|
||||
{
|
||||
snlp.fft_cfg.twiddles.clear();
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
nlp()
|
||||
|
||||
Determines the pitch in samples using the Non Linear Pitch (NLP)
|
||||
algorithm [1]. Returns the fundamental in Hz. Note that the actual
|
||||
pitch estimate is for the centre of the M sample Sn[] vector, not
|
||||
the current N sample input vector. This is (I think) a delay of 2.5
|
||||
frames with N=80 samples. You should align further analysis using
|
||||
this pitch estimate to be centred on the middle of Sn[].
|
||||
|
||||
Two post processors have been tried, the MBE version (as discussed
|
||||
in [1]), and a post processor that checks sub-multiples. Both
|
||||
suffer occasional gross pitch errors (i.e. neither are perfect). In
|
||||
the presence of background noise the sub-multiple algorithm tends
|
||||
towards low F0 which leads to better sounding background noise than
|
||||
the MBE post processor.
|
||||
|
||||
A good way to test and develop the NLP pitch estimator is using the
|
||||
tnlp (codec2/unittest) and the codec2/octave/plnlp.m Octave script.
|
||||
|
||||
A pitch tracker searching a few frames forward and backward in time
|
||||
would be a useful addition.
|
||||
|
||||
References:
|
||||
|
||||
[1] http://rowetel.com/downloads/1997_rowe_phd_thesis.pdf Chapter 4
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
float Cnlp::nlp(
|
||||
float Sn[], /* input speech vector */
|
||||
int n, /* frames shift (no. new samples in Sn[]) */
|
||||
float *pitch, /* estimated pitch period in samples at current Fs */
|
||||
// std::complex<float> Sw[], /* Freq domain version of Sn[] */
|
||||
// float W[], /* Freq domain window */
|
||||
float *prev_f0 /* previous pitch f0 in Hz, memory for pitch tracking */
|
||||
)
|
||||
{
|
||||
float notch; /* current notch filter output */
|
||||
std::complex<float> Fw[PE_FFT_SIZE]; /* DFT of squared signal (input/output) */
|
||||
float gmax;
|
||||
int gmax_bin;
|
||||
int m, i, j;
|
||||
float best_f0;
|
||||
|
||||
m = snlp.m;
|
||||
|
||||
/* Square, notch filter at DC, and LP filter vector */
|
||||
|
||||
/* If running at 16 kHz decimate to 8 kHz, as NLP ws designed for
|
||||
Fs = 8kHz. The decimating filter introduces about 3ms of delay,
|
||||
that shouldn't be a problem as pitch changes slowly. */
|
||||
|
||||
if (snlp.Fs == 8000)
|
||||
{
|
||||
/* Square latest input samples */
|
||||
|
||||
for(i=m-n; i<m; i++)
|
||||
{
|
||||
snlp.sq[i] = Sn[i]*Sn[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(snlp.Fs == 16000);
|
||||
|
||||
/* re-sample at 8 KHz */
|
||||
|
||||
for(i=0; i<n; i++)
|
||||
{
|
||||
snlp.Sn16k[FDMDV_OS_TAPS_16K+i] = Sn[m-n+i];
|
||||
}
|
||||
|
||||
m /= 2;
|
||||
n /= 2;
|
||||
|
||||
float Sn8k[n];
|
||||
fdmdv_16_to_8(Sn8k, &snlp.Sn16k[FDMDV_OS_TAPS_16K], n);
|
||||
|
||||
/* Square latest input samples */
|
||||
|
||||
for(i=m-n, j=0; i<m; i++, j++)
|
||||
{
|
||||
snlp.sq[i] = Sn8k[j]*Sn8k[j];
|
||||
}
|
||||
assert(j <= n);
|
||||
}
|
||||
|
||||
for(i=m-n; i<m; i++) /* notch filter at DC */
|
||||
{
|
||||
notch = snlp.sq[i] - snlp.mem_x;
|
||||
notch += COEFF*snlp.mem_y;
|
||||
snlp.mem_x = snlp.sq[i];
|
||||
snlp.mem_y = notch;
|
||||
snlp.sq[i] = notch + 1.0; /* With 0 input vectors to codec,
|
||||
kiss_fft() would take a long
|
||||
time to execute when running in
|
||||
real time. Problem was traced
|
||||
to kiss_fft function call in
|
||||
this function. Adding this small
|
||||
constant fixed problem. Not
|
||||
exactly sure why. */
|
||||
}
|
||||
|
||||
for(i=m-n; i<m; i++) /* FIR filter vector */
|
||||
{
|
||||
|
||||
for(j=0; j<NLP_NTAP-1; j++)
|
||||
snlp.mem_fir[j] = snlp.mem_fir[j+1];
|
||||
snlp.mem_fir[NLP_NTAP-1] = snlp.sq[i];
|
||||
|
||||
snlp.sq[i] = 0.0;
|
||||
for(j=0; j<NLP_NTAP; j++)
|
||||
snlp.sq[i] += snlp.mem_fir[j]*nlp_fir[j];
|
||||
}
|
||||
|
||||
/* Decimate and DFT */
|
||||
|
||||
for(i=0; i<PE_FFT_SIZE; i++)
|
||||
{
|
||||
Fw[i].real(0);
|
||||
Fw[i].imag(0);
|
||||
}
|
||||
for(i=0; i<m/DEC; i++)
|
||||
{
|
||||
Fw[i].real(snlp.sq[i*DEC]*snlp.w[i]);
|
||||
}
|
||||
|
||||
// FIXME: check if this can be converted to a real fft
|
||||
// since all imag inputs are 0
|
||||
codec2_fft_inplace(snlp.fft_cfg, Fw);
|
||||
|
||||
for(i=0; i<PE_FFT_SIZE; i++)
|
||||
Fw[i].real(Fw[i].real() * Fw[i].real() + Fw[i].imag() * Fw[i].imag());
|
||||
|
||||
/* todo: express everything in f0, as pitch in samples is dep on Fs */
|
||||
|
||||
int pmin = floor(SAMPLE_RATE*P_MIN_S);
|
||||
int pmax = floor(SAMPLE_RATE*P_MAX_S);
|
||||
|
||||
/* find global peak */
|
||||
|
||||
gmax = 0.0;
|
||||
gmax_bin = PE_FFT_SIZE*DEC/pmax;
|
||||
for(i=PE_FFT_SIZE*DEC/pmax; i<=PE_FFT_SIZE*DEC/pmin; i++)
|
||||
{
|
||||
if (Fw[i].real() > gmax)
|
||||
{
|
||||
gmax = Fw[i].real();
|
||||
gmax_bin = i;
|
||||
}
|
||||
}
|
||||
|
||||
best_f0 = post_process_sub_multiples(Fw, pmax, gmax, gmax_bin, prev_f0);
|
||||
|
||||
/* Shift samples in buffer to make room for new samples */
|
||||
|
||||
for(i=0; i<m-n; i++)
|
||||
snlp.sq[i] = snlp.sq[i+n];
|
||||
|
||||
/* return pitch period in samples and F0 estimate */
|
||||
|
||||
*pitch = (float)snlp.Fs/best_f0;
|
||||
|
||||
*prev_f0 = best_f0;
|
||||
|
||||
return(best_f0);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
post_process_sub_multiples()
|
||||
|
||||
Given the global maximma of Fw[] we search integer submultiples for
|
||||
local maxima. If local maxima exist and they are above an
|
||||
experimentally derived threshold (OK a magic number I pulled out of
|
||||
the air) we choose the submultiple as the F0 estimate.
|
||||
|
||||
The rational for this is that the lowest frequency peak of Fw[]
|
||||
should be F0, as Fw[] can be considered the autocorrelation function
|
||||
of Sw[] (the speech spectrum). However sometimes due to phase
|
||||
effects the lowest frequency maxima may not be the global maxima.
|
||||
|
||||
This works OK in practice and favours low F0 values in the presence
|
||||
of background noise which means the sinusoidal codec does an OK job
|
||||
of synthesising the background noise. High F0 in background noise
|
||||
tends to sound more periodic introducing annoying artifacts.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
float Cnlp::post_process_sub_multiples(std::complex<float> Fw[], int pmax, float gmax, int gmax_bin, float *prev_f0)
|
||||
{
|
||||
int min_bin, cmax_bin;
|
||||
int mult;
|
||||
float thresh, best_f0;
|
||||
int b, bmin, bmax, lmax_bin;
|
||||
float lmax;
|
||||
int prev_f0_bin;
|
||||
|
||||
/* post process estimate by searching submultiples */
|
||||
|
||||
mult = 2;
|
||||
min_bin = PE_FFT_SIZE*DEC/pmax;
|
||||
cmax_bin = gmax_bin;
|
||||
prev_f0_bin = *prev_f0*(PE_FFT_SIZE*DEC)/SAMPLE_RATE;
|
||||
|
||||
while(gmax_bin/mult >= min_bin)
|
||||
{
|
||||
|
||||
b = gmax_bin/mult; /* determine search interval */
|
||||
bmin = 0.8*b;
|
||||
bmax = 1.2*b;
|
||||
if (bmin < min_bin)
|
||||
bmin = min_bin;
|
||||
|
||||
/* lower threshold to favour previous frames pitch estimate,
|
||||
this is a form of pitch tracking */
|
||||
|
||||
if ((prev_f0_bin > bmin) && (prev_f0_bin < bmax))
|
||||
thresh = CNLP*0.5*gmax;
|
||||
else
|
||||
thresh = CNLP*gmax;
|
||||
|
||||
lmax = 0;
|
||||
lmax_bin = bmin;
|
||||
for (b=bmin; b<=bmax; b++) /* look for maximum in interval */
|
||||
if (Fw[b].real() > lmax)
|
||||
{
|
||||
lmax = Fw[b].real();
|
||||
lmax_bin = b;
|
||||
}
|
||||
|
||||
if (lmax > thresh)
|
||||
if ((lmax > Fw[lmax_bin-1].real()) && (lmax > Fw[lmax_bin+1].real()))
|
||||
{
|
||||
cmax_bin = lmax_bin;
|
||||
}
|
||||
|
||||
mult++;
|
||||
}
|
||||
|
||||
best_f0 = (float)cmax_bin*SAMPLE_RATE/(PE_FFT_SIZE*DEC);
|
||||
|
||||
return best_f0;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: fdmdv_16_to_8()
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 9 May 2012
|
||||
|
||||
Changes the sample rate of a signal from 16 to 8 kHz.
|
||||
|
||||
n is the number of samples at the 8 kHz rate, there are FDMDV_OS*n
|
||||
samples at the 48 kHz rate. As above however a memory of
|
||||
FDMDV_OS_TAPS samples is reqd for in16k[] (see t16_8.c unit test as example).
|
||||
|
||||
Low pass filter the 16 kHz signal at 4 kHz using the same filter as
|
||||
the upsampler, then just output every FDMDV_OS-th filtered sample.
|
||||
|
||||
Note: this function copied from fdmdv.c, included in nlp.c as a convenience
|
||||
to avoid linking with another source file.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void Cnlp::fdmdv_16_to_8(float out8k[], float in16k[], int n)
|
||||
{
|
||||
float acc;
|
||||
int i,j,k;
|
||||
|
||||
for(i=0, k=0; k<n; i+=FDMDV_OS, k++)
|
||||
{
|
||||
acc = 0.0;
|
||||
for(j=0; j<FDMDV_OS_TAPS_16K; j++)
|
||||
acc += fdmdv_os_filter[j]*in16k[i-j];
|
||||
out8k[k] = acc;
|
||||
}
|
||||
|
||||
/* update filter memory */
|
||||
|
||||
for(i=-FDMDV_OS_TAPS_16K; i<0; i++)
|
||||
in16k[i] = in16k[i + n*FDMDV_OS];
|
||||
}
|
||||
|
||||
// there is a little overhead for inplace kiss_fft but this is
|
||||
// on the powerful platforms like the Raspberry or even x86 PC based ones
|
||||
// not noticeable
|
||||
// the reduced usage of RAM and increased performance on STM32 platforms
|
||||
// should be worth it.
|
||||
void Cnlp::codec2_fft_inplace(FFT_STATE &cfg, std::complex<float> *inout)
|
||||
{
|
||||
std::complex<float> in[512];
|
||||
// decide whether to use the local stack based buffer for in
|
||||
// or to allow kiss_fft to allocate RAM
|
||||
// second part is just to play safe since first method
|
||||
// is much faster and uses less RAM
|
||||
if (cfg.nfft <= 512)
|
||||
{
|
||||
memcpy(in, inout, cfg.nfft*sizeof(std::complex<float>));
|
||||
kiss.fft(cfg, in, inout);
|
||||
}
|
||||
else
|
||||
{
|
||||
kiss.fft(cfg, inout, inout);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FILE........: nlp.c
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 23/3/93
|
||||
|
||||
Non Linear Pitch (NLP) estimation functions.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
Copyright (C) 2009 David Rowe
|
||||
|
||||
All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License version 2.1, as
|
||||
published by the Free Software Foundation. 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 Lesser General Public License
|
||||
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __NLP__
|
||||
#define __NLP__
|
||||
|
||||
#include <complex>
|
||||
#include <vector>
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
DEFINES
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#define PMAX_M 320 /* maximum NLP analysis window size */
|
||||
#define COEFF 0.95 /* notch filter parameter */
|
||||
#define PE_FFT_SIZE 512 /* DFT size for pitch estimation */
|
||||
#define DEC 5 /* decimation factor */
|
||||
#define SAMPLE_RATE 8000
|
||||
#define PI 3.141592654 /* mathematical constant */
|
||||
//#define T 0.1 /* threshold for local minima candidate */
|
||||
#define F0_MAX 500
|
||||
#define CNLP 0.3 /* post processor constant */
|
||||
#define NLP_NTAP 48 /* Decimation LPF order */
|
||||
|
||||
/* 8 to 16 kHz sample rate conversion */
|
||||
|
||||
#define FDMDV_OS 2 /* oversampling rate */
|
||||
#define FDMDV_OS_TAPS_16K 48 /* number of OS filter taps at 16kHz */
|
||||
#define FDMDV_OS_TAPS_8K (FDMDV_OS_TAPS_16K/FDMDV_OS) /* number of OS filter taps at 8kHz */
|
||||
|
||||
|
||||
using NLP = struct nlp_tag
|
||||
{
|
||||
int Fs; /* sample rate in Hz */
|
||||
int m;
|
||||
float w[PMAX_M/DEC]; /* DFT window */
|
||||
float sq[PMAX_M]; /* squared speech samples */
|
||||
float mem_x,mem_y; /* memory for notch filter */
|
||||
float mem_fir[NLP_NTAP]; /* decimation FIR filter memory */
|
||||
FFT_STATE fft_cfg; /* kiss FFT config */
|
||||
std::vector<float> Sn16k; /* Fs=16kHz input speech vector */
|
||||
};
|
||||
|
||||
|
||||
class Cnlp {
|
||||
public:
|
||||
void nlp_create(C2CONST *c2const);
|
||||
void nlp_destroy();
|
||||
float nlp(float Sn[], int n, float *pitch_samples, float *prev_f0);
|
||||
void codec2_fft_inplace(FFT_STATE &cfg, std::complex<float> *inout);
|
||||
|
||||
private:
|
||||
float post_process_sub_multiples(std::complex<float> Fw[], int pmax, float gmax, int gmax_bin, float *prev_f0);
|
||||
void fdmdv_16_to_8(float out8k[], float in16k[], int n);
|
||||
|
||||
NLP snlp;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
Copyright (C) 2010 Perens LLC <bruce@perens.com>
|
||||
|
||||
All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License version 2.1, as
|
||||
published by the Free Software Foundation. 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 Lesser General Public License
|
||||
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "defines.h"
|
||||
#include "quantise.h"
|
||||
#include <stdio.h>
|
||||
|
||||
/* Compile-time constants */
|
||||
/* Size of unsigned char in bits. Assumes 8 bits-per-char. */
|
||||
static const unsigned int WordSize = 8;
|
||||
|
||||
/* Mask to pick the bit component out of bitIndex. */
|
||||
static const unsigned int IndexMask = 0x7;
|
||||
|
||||
/* Used to pick the word component out of bitIndex. */
|
||||
static const unsigned int ShiftRight = 3;
|
||||
|
||||
/** Pack a bit field into a bit string, encoding the field in Gray code.
|
||||
*
|
||||
* The output is an array of unsigned char data. The fields are efficiently
|
||||
* packed into the bit string. The Gray coding is a naive attempt to reduce
|
||||
* the effect of single-bit errors, we expect to do a better job as the
|
||||
* codec develops.
|
||||
*
|
||||
* This code would be simpler if it just set one bit at a time in the string,
|
||||
* but would hit the same cache line more often. I'm not sure the complexity
|
||||
* gains us anything here.
|
||||
*
|
||||
* Although field is currently of int type rather than unsigned for
|
||||
* compatibility with the rest of the code, indices are always expected to
|
||||
* be >= 0.
|
||||
*/
|
||||
void CQuantize::pack(
|
||||
unsigned char *bitArray, /* The output bit string. */
|
||||
unsigned int *bitIndex, /* Index into the string in BITS, not bytes.*/
|
||||
int field, /* The bit field to be packed. */
|
||||
unsigned int fieldWidth /* Width of the field in BITS, not bytes. */
|
||||
)
|
||||
{
|
||||
pack_natural_or_gray(bitArray, bitIndex, field, fieldWidth, 1);
|
||||
}
|
||||
|
||||
void CQuantize::pack_natural_or_gray(
|
||||
unsigned char *bitArray, /* The output bit string. */
|
||||
unsigned int *bitIndex, /* Index into the string in BITS, not bytes.*/
|
||||
int field, /* The bit field to be packed. */
|
||||
unsigned int fieldWidth, /* Width of the field in BITS, not bytes. */
|
||||
unsigned int gray /* non-zero for gray coding */
|
||||
)
|
||||
{
|
||||
if (gray)
|
||||
{
|
||||
/* Convert the field to Gray code */
|
||||
field = (field >> 1) ^ field;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
unsigned int bI = *bitIndex;
|
||||
unsigned int bitsLeft = WordSize - (bI & IndexMask);
|
||||
unsigned int sliceWidth = bitsLeft < fieldWidth ? bitsLeft : fieldWidth;
|
||||
unsigned int wordIndex = bI >> ShiftRight;
|
||||
|
||||
bitArray[wordIndex] |= ((unsigned char)((field >> (fieldWidth - sliceWidth)) << (bitsLeft - sliceWidth)));
|
||||
|
||||
*bitIndex = bI + sliceWidth;
|
||||
fieldWidth -= sliceWidth;
|
||||
}
|
||||
while ( fieldWidth != 0 );
|
||||
}
|
||||
|
||||
/** Unpack a field from a bit string, converting from Gray code to binary.
|
||||
*
|
||||
*/
|
||||
int CQuantize::unpack(
|
||||
const unsigned char *bitArray, /* The input bit string. */
|
||||
unsigned int *bitIndex, /* Index into the string in BITS, not bytes.*/
|
||||
unsigned int fieldWidth/* Width of the field in BITS, not bytes. */
|
||||
)
|
||||
{
|
||||
return unpack_natural_or_gray(bitArray, bitIndex, fieldWidth, 1);
|
||||
}
|
||||
|
||||
/** Unpack a field from a bit string, to binary, optionally using
|
||||
* natural or Gray code.
|
||||
*
|
||||
*/
|
||||
int CQuantize::unpack_natural_or_gray(
|
||||
const unsigned char *bitArray, /* The input bit string. */
|
||||
unsigned int *bitIndex, /* Index into the string in BITS, not bytes.*/
|
||||
unsigned int fieldWidth,/* Width of the field in BITS, not bytes. */
|
||||
unsigned int gray /* non-zero for Gray coding */
|
||||
)
|
||||
{
|
||||
unsigned int field = 0;
|
||||
unsigned int t;
|
||||
|
||||
do
|
||||
{
|
||||
unsigned int bI = *bitIndex;
|
||||
unsigned int bitsLeft = WordSize - (bI & IndexMask);
|
||||
unsigned int sliceWidth = bitsLeft < fieldWidth ? bitsLeft : fieldWidth;
|
||||
|
||||
field |= (((bitArray[bI >> ShiftRight] >> (bitsLeft - sliceWidth)) & ((1 << sliceWidth) - 1)) << (fieldWidth - sliceWidth));
|
||||
|
||||
*bitIndex = bI + sliceWidth;
|
||||
fieldWidth -= sliceWidth;
|
||||
}
|
||||
while ( fieldWidth != 0 );
|
||||
|
||||
if (gray)
|
||||
{
|
||||
/* Convert from Gray code to binary. Works for maximum 8-bit fields. */
|
||||
t = field ^ (field >> 8);
|
||||
t ^= (t >> 4);
|
||||
t ^= (t >> 2);
|
||||
t ^= (t >> 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
t = field;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
|
@ -0,0 +1,247 @@
|
|||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "qbase.h"
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
quantise
|
||||
|
||||
Quantises vec by choosing the nearest vector in codebook cb, and
|
||||
returns the vector index. The squared error of the quantised vector
|
||||
is added to se.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
long CQbase::quantise(const float *cb, float vec[], float w[], int k, int m, float *se)
|
||||
/* float cb[][K]; current VQ codebook */
|
||||
/* float vec[]; vector to quantise */
|
||||
/* float w[]; weighting vector */
|
||||
/* int k; dimension of vectors */
|
||||
/* int m; size of codebook */
|
||||
/* float *se; accumulated squared error */
|
||||
{
|
||||
float e; /* current error */
|
||||
long besti; /* best index so far */
|
||||
float beste; /* best error so far */
|
||||
long j;
|
||||
int i;
|
||||
float diff;
|
||||
|
||||
besti = 0;
|
||||
beste = 1E32;
|
||||
for(j=0; j<m; j++)
|
||||
{
|
||||
e = 0.0;
|
||||
for(i=0; i<k; i++)
|
||||
{
|
||||
diff = cb[j*k+i]-vec[i];
|
||||
e += (diff*w[i] * diff*w[i]);
|
||||
}
|
||||
if (e < beste)
|
||||
{
|
||||
beste = e;
|
||||
besti = j;
|
||||
}
|
||||
}
|
||||
|
||||
*se += beste;
|
||||
|
||||
return(besti);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: encode_WoE()
|
||||
AUTHOR......: Jean-Marc Valin & David Rowe
|
||||
DATE CREATED: 11 May 2012
|
||||
|
||||
Joint Wo and LPC energy vector quantiser developed my Jean-Marc
|
||||
Valin. Returns index, and updated states xq[].
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
int CQbase::encode_WoE(MODEL *model, float e, float xq[])
|
||||
{
|
||||
int i, n1;
|
||||
float x[2];
|
||||
float err[2];
|
||||
float w[2];
|
||||
const float *codebook1 = ge_cb[0].cb;
|
||||
int nb_entries = ge_cb[0].m;
|
||||
int ndim = ge_cb[0].k;
|
||||
|
||||
assert((1<<WO_E_BITS) == nb_entries);
|
||||
|
||||
if (e < 0.0) e = 0; /* occasional small negative energies due LPC round off I guess */
|
||||
|
||||
x[0] = log10f((model->Wo/PI)*4000.0/50.0)/log10f(2);
|
||||
x[1] = 10.0*log10f(1e-4 + e);
|
||||
|
||||
compute_weights2(x, xq, w);
|
||||
for (i=0; i<ndim; i++)
|
||||
err[i] = x[i]-ge_coeff[i]*xq[i];
|
||||
n1 = find_nearest_weighted(codebook1, nb_entries, err, w, ndim);
|
||||
|
||||
for (i=0; i<ndim; i++)
|
||||
{
|
||||
xq[i] = ge_coeff[i]*xq[i] + codebook1[ndim*n1+i];
|
||||
err[i] -= codebook1[ndim*n1+i];
|
||||
}
|
||||
|
||||
//printf("enc: %f %f (%f)(%f) \n", xq[0], xq[1], e, 10.0*log10(1e-4 + e));
|
||||
return n1;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: decode_WoE()
|
||||
AUTHOR......: Jean-Marc Valin & David Rowe
|
||||
DATE CREATED: 11 May 2012
|
||||
|
||||
Joint Wo and LPC energy vector quantiser developed my Jean-Marc
|
||||
Valin. Given index and states xq[], returns Wo & E, and updates
|
||||
states xq[].
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void CQbase::decode_WoE(C2CONST *c2const, MODEL *model, float *e, float xq[], int n1)
|
||||
{
|
||||
int i;
|
||||
const float *codebook1 = ge_cb[0].cb;
|
||||
int ndim = ge_cb[0].k;
|
||||
float Wo_min = c2const->Wo_min;
|
||||
float Wo_max = c2const->Wo_max;
|
||||
|
||||
for (i=0; i<ndim; i++)
|
||||
{
|
||||
xq[i] = ge_coeff[i]*xq[i] + codebook1[ndim*n1+i];
|
||||
}
|
||||
|
||||
//printf("dec: %f %f\n", xq[0], xq[1]);
|
||||
model->Wo = powf(2.0, xq[0])*(PI*50.0)/4000.0;
|
||||
|
||||
/* bit errors can make us go out of range leading to all sorts of
|
||||
probs like seg faults */
|
||||
|
||||
if (model->Wo > Wo_max) model->Wo = Wo_max;
|
||||
if (model->Wo < Wo_min) model->Wo = Wo_min;
|
||||
|
||||
model->L = PI/model->Wo; /* if we quantise Wo re-compute L */
|
||||
|
||||
*e = exp10f(xq[1]/10.0);
|
||||
}
|
||||
|
||||
void CQbase::compute_weights2(const float *x, const float *xp, float *w)
|
||||
{
|
||||
w[0] = 30;
|
||||
w[1] = 1;
|
||||
if (x[1]<0)
|
||||
{
|
||||
w[0] *= .6;
|
||||
w[1] *= .3;
|
||||
}
|
||||
if (x[1]<-10)
|
||||
{
|
||||
w[0] *= .3;
|
||||
w[1] *= .3;
|
||||
}
|
||||
/* Higher weight if pitch is stable */
|
||||
if (fabsf(x[0]-xp[0])<.2)
|
||||
{
|
||||
w[0] *= 2;
|
||||
w[1] *= 1.5;
|
||||
}
|
||||
else if (fabsf(x[0]-xp[0])>.5) /* Lower if not stable */
|
||||
{
|
||||
w[0] *= .5;
|
||||
}
|
||||
|
||||
/* Lower weight for low energy */
|
||||
if (x[1] < xp[1]-10)
|
||||
{
|
||||
w[1] *= .5;
|
||||
}
|
||||
if (x[1] < xp[1]-20)
|
||||
{
|
||||
w[1] *= .5;
|
||||
}
|
||||
|
||||
//w[0] = 30;
|
||||
//w[1] = 1;
|
||||
|
||||
/* Square the weights because it's applied on the squared error */
|
||||
w[0] *= w[0];
|
||||
w[1] *= w[1];
|
||||
|
||||
}
|
||||
|
||||
int CQbase::find_nearest_weighted(const float *codebook, int nb_entries, float *x, const float *w, int ndim)
|
||||
{
|
||||
int i, j;
|
||||
float min_dist = 1e15;
|
||||
int nearest = 0;
|
||||
|
||||
for (i=0; i<nb_entries; i++)
|
||||
{
|
||||
float dist=0;
|
||||
for (j=0; j<ndim; j++)
|
||||
dist += w[j]*(x[j]-codebook[i*ndim+j])*(x[j]-codebook[i*ndim+j]);
|
||||
if (dist<min_dist)
|
||||
{
|
||||
min_dist = dist;
|
||||
nearest = i;
|
||||
}
|
||||
}
|
||||
return nearest;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: encode_log_Wo()
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 22/8/2010
|
||||
|
||||
Encodes Wo in the log domain using a WO_LEVELS quantiser.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
int CQbase::encode_log_Wo(C2CONST *c2const, float Wo, int bits)
|
||||
{
|
||||
int index, Wo_levels = 1<<bits;
|
||||
float Wo_min = c2const->Wo_min;
|
||||
float Wo_max = c2const->Wo_max;
|
||||
float norm;
|
||||
|
||||
norm = (log10f(Wo) - log10f(Wo_min))/(log10f(Wo_max) - log10f(Wo_min));
|
||||
index = floorf(Wo_levels * norm + 0.5);
|
||||
if (index < 0 ) index = 0;
|
||||
if (index > (Wo_levels-1)) index = Wo_levels-1;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: decode_log_Wo()
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 22/8/2010
|
||||
|
||||
Decodes Wo using a WO_LEVELS quantiser in the log domain.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
float CQbase::decode_log_Wo(C2CONST *c2const, int index, int bits)
|
||||
{
|
||||
float Wo_min = c2const->Wo_min;
|
||||
float Wo_max = c2const->Wo_max;
|
||||
float step;
|
||||
float Wo;
|
||||
int Wo_levels = 1<<bits;
|
||||
|
||||
step = (log10f(Wo_max) - log10f(Wo_min))/Wo_levels;
|
||||
Wo = log10f(Wo_min) + step*(index);
|
||||
|
||||
return exp10f(Wo);
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
#ifndef QBASE_H
|
||||
#define QBASE_H
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
#define WO_BITS 7
|
||||
#define WO_LEVELS (1<<WO_BITS)
|
||||
#define WO_DT_BITS 3
|
||||
|
||||
#define E_BITS 5
|
||||
#define E_LEVELS (1<<E_BITS)
|
||||
#define E_MIN_DB -10.0
|
||||
#define E_MAX_DB 40.0
|
||||
|
||||
#define LSP_SCALAR_INDEXES 10
|
||||
#define LSPD_SCALAR_INDEXES 10
|
||||
#define LSP_PRED_VQ_INDEXES 3
|
||||
|
||||
#define WO_E_BITS 8
|
||||
|
||||
#define LPCPF_GAMMA 0.5
|
||||
#define LPCPF_BETA 0.2
|
||||
|
||||
class CQbase {
|
||||
public:
|
||||
int encode_WoE(MODEL *model, float e, float xq[]);
|
||||
void decode_WoE(C2CONST *c2const, MODEL *model, float *e, float xq[], int n1);
|
||||
int encode_log_Wo(C2CONST *c2const, float Wo, int bits);
|
||||
float decode_log_Wo(C2CONST *c2const, int index, int bits);
|
||||
protected:
|
||||
long quantise(const float * cb, float vec[], float w[], int k, int m, float *se);
|
||||
void compute_weights2(const float *x, const float *xp, float *w);
|
||||
int find_nearest_weighted(const float *codebook, int nb_entries, float *x, const float *w, int ndim);
|
||||
|
||||
const float ge_coeff[2] = { 0.8, 0.9 };
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,897 @@
|
|||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FILE........: quantise.c
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 31/5/92
|
||||
|
||||
Quantisation functions for the sinusoidal coder.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License version 2.1, as
|
||||
published by the Free Software Foundation. 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 Lesser General Public License
|
||||
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "defines.h"
|
||||
#include "quantise.h"
|
||||
#include "lpc.h"
|
||||
#include "kiss_fft.h"
|
||||
|
||||
extern CKissFFT kiss;
|
||||
|
||||
#define LSP_DELTA1 0.01 /* grid spacing for LSP root searches */
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTIONS
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
int CQuantize::lsp_bits(int i)
|
||||
{
|
||||
return lsp_cb[i].log2m;
|
||||
}
|
||||
|
||||
int CQuantize::lspd_bits(int i)
|
||||
{
|
||||
return lsp_cbd[i].log2m;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
encode_lspds_scalar()
|
||||
|
||||
Scalar/VQ LSP difference quantiser.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void CQuantize::encode_lspds_scalar(int indexes[], float lsp[], int order)
|
||||
{
|
||||
int i,k,m;
|
||||
float lsp_hz[order];
|
||||
float lsp__hz[order];
|
||||
float dlsp[order];
|
||||
float dlsp_[order];
|
||||
float wt[order];
|
||||
const float *cb;
|
||||
float se;
|
||||
|
||||
for(i=0; i<order; i++)
|
||||
{
|
||||
wt[i] = 1.0;
|
||||
}
|
||||
|
||||
/* convert from radians to Hz so we can use human readable
|
||||
frequencies */
|
||||
|
||||
for(i=0; i<order; i++)
|
||||
lsp_hz[i] = (4000.0/PI)*lsp[i];
|
||||
|
||||
wt[0] = 1.0;
|
||||
for(i=0; i<order; i++)
|
||||
{
|
||||
|
||||
/* find difference from previous qunatised lsp */
|
||||
|
||||
if (i)
|
||||
dlsp[i] = lsp_hz[i] - lsp__hz[i-1];
|
||||
else
|
||||
dlsp[0] = lsp_hz[0];
|
||||
|
||||
k = lsp_cbd[i].k;
|
||||
m = lsp_cbd[i].m;
|
||||
cb = lsp_cbd[i].cb;
|
||||
indexes[i] = quantise(cb, &dlsp[i], wt, k, m, &se);
|
||||
dlsp_[i] = cb[indexes[i]*k];
|
||||
|
||||
|
||||
if (i)
|
||||
lsp__hz[i] = lsp__hz[i-1] + dlsp_[i];
|
||||
else
|
||||
lsp__hz[0] = dlsp_[0];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void CQuantize::decode_lspds_scalar( float lsp_[], int indexes[], int order)
|
||||
{
|
||||
int i,k;
|
||||
float lsp__hz[order];
|
||||
float dlsp_[order];
|
||||
const float *cb;
|
||||
|
||||
for(i=0; i<order; i++)
|
||||
{
|
||||
|
||||
k = lsp_cbd[i].k;
|
||||
cb = lsp_cbd[i].cb;
|
||||
dlsp_[i] = cb[indexes[i]*k];
|
||||
|
||||
if (i)
|
||||
lsp__hz[i] = lsp__hz[i-1] + dlsp_[i];
|
||||
else
|
||||
lsp__hz[0] = dlsp_[0];
|
||||
|
||||
lsp_[i] = (PI/4000.0)*lsp__hz[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||
#define MAX_ENTRIES 16384
|
||||
|
||||
void CQuantize::compute_weights(const float *x, float *w, int ndim)
|
||||
{
|
||||
int i;
|
||||
w[0] = MIN(x[0], x[1]-x[0]);
|
||||
for (i=1; i<ndim-1; i++)
|
||||
w[i] = MIN(x[i]-x[i-1], x[i+1]-x[i]);
|
||||
w[ndim-1] = MIN(x[ndim-1]-x[ndim-2], PI-x[ndim-1]);
|
||||
|
||||
for (i=0; i<ndim; i++)
|
||||
w[i] = 1./(.01+w[i]);
|
||||
}
|
||||
|
||||
int CQuantize::find_nearest(const float *codebook, int nb_entries, float *x, int ndim)
|
||||
{
|
||||
int i, j;
|
||||
float min_dist = 1e15;
|
||||
int nearest = 0;
|
||||
|
||||
for (i=0; i<nb_entries; i++)
|
||||
{
|
||||
float dist=0;
|
||||
for (j=0; j<ndim; j++)
|
||||
dist += (x[j]-codebook[i*ndim+j])*(x[j]-codebook[i*ndim+j]);
|
||||
if (dist<min_dist)
|
||||
{
|
||||
min_dist = dist;
|
||||
nearest = i;
|
||||
}
|
||||
}
|
||||
return nearest;
|
||||
}
|
||||
|
||||
int CQuantize::check_lsp_order(float lsp[], int order)
|
||||
{
|
||||
int i;
|
||||
float tmp;
|
||||
int swaps = 0;
|
||||
|
||||
for(i=1; i<order; i++)
|
||||
if (lsp[i] < lsp[i-1])
|
||||
{
|
||||
//fprintf(stderr, "swap %d\n",i);
|
||||
swaps++;
|
||||
tmp = lsp[i-1];
|
||||
lsp[i-1] = lsp[i]-0.1;
|
||||
lsp[i] = tmp+0.1;
|
||||
i = 1; /* start check again, as swap may have caused out of order */
|
||||
}
|
||||
|
||||
return swaps;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
lpc_post_filter()
|
||||
|
||||
Applies a post filter to the LPC synthesis filter power spectrum
|
||||
Pw, which supresses the inter-formant energy.
|
||||
|
||||
The algorithm is from p267 (Section 8.6) of "Digital Speech",
|
||||
edited by A.M. Kondoz, 1994 published by Wiley and Sons. Chapter 8
|
||||
of this text is on the MBE vocoder, and this is a freq domain
|
||||
adaptation of post filtering commonly used in CELP.
|
||||
|
||||
I used the Octave simulation lpcpf.m to get an understanding of the
|
||||
algorithm.
|
||||
|
||||
Requires two more FFTs which is significantly more MIPs. However
|
||||
it should be possible to implement this more efficiently in the
|
||||
time domain. Just not sure how to handle relative time delays
|
||||
between the synthesis stage and updating these coeffs. A smaller
|
||||
FFT size might also be accetable to save CPU.
|
||||
|
||||
TODO:
|
||||
[ ] sync var names between Octave and C version
|
||||
[ ] doc gain normalisation
|
||||
[ ] I think the first FFT is not rqd as we do the same
|
||||
thing in aks_to_M2().
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void CQuantize::lpc_post_filter(FFTR_STATE *fftr_fwd_cfg, float Pw[], float ak[], int order, float beta, float gamma, int bass_boost, float E)
|
||||
{
|
||||
int i;
|
||||
float x[FFT_ENC]; /* input to FFTs */
|
||||
std::complex<float> Ww[FFT_ENC/2+1]; /* weighting spectrum */
|
||||
float Rw[FFT_ENC/2+1]; /* R = WA */
|
||||
float e_before, e_after, gain;
|
||||
float Pfw;
|
||||
float max_Rw, min_Rw;
|
||||
float coeff;
|
||||
|
||||
/* Determine weighting filter spectrum W(exp(jw)) ---------------*/
|
||||
|
||||
for(i=0; i<FFT_ENC; i++)
|
||||
{
|
||||
x[i] = 0.0;
|
||||
}
|
||||
|
||||
x[0] = ak[0];
|
||||
coeff = gamma;
|
||||
for(i=1; i<=order; i++)
|
||||
{
|
||||
x[i] = ak[i] * coeff;
|
||||
coeff *= gamma;
|
||||
}
|
||||
kiss.fftr(*fftr_fwd_cfg, x, Ww);
|
||||
|
||||
for(i=0; i<FFT_ENC/2; i++)
|
||||
{
|
||||
Ww[i].real(Ww[i].real() * Ww[i].real() + Ww[i].imag() * Ww[i].imag());
|
||||
}
|
||||
|
||||
/* Determined combined filter R = WA ---------------------------*/
|
||||
|
||||
max_Rw = 0.0;
|
||||
min_Rw = 1E32;
|
||||
for(i=0; i<FFT_ENC/2; i++)
|
||||
{
|
||||
Rw[i] = sqrtf(Ww[i].real() * Pw[i]);
|
||||
if (Rw[i] > max_Rw)
|
||||
max_Rw = Rw[i];
|
||||
if (Rw[i] < min_Rw)
|
||||
min_Rw = Rw[i];
|
||||
|
||||
}
|
||||
|
||||
/* create post filter mag spectrum and apply ------------------*/
|
||||
|
||||
/* measure energy before post filtering */
|
||||
|
||||
e_before = 1E-4;
|
||||
for(i=0; i<FFT_ENC/2; i++)
|
||||
e_before += Pw[i];
|
||||
|
||||
/* apply post filter and measure energy */
|
||||
|
||||
|
||||
e_after = 1E-4;
|
||||
for(i=0; i<FFT_ENC/2; i++)
|
||||
{
|
||||
Pfw = powf(Rw[i], beta);
|
||||
Pw[i] *= Pfw * Pfw;
|
||||
e_after += Pw[i];
|
||||
}
|
||||
gain = e_before/e_after;
|
||||
|
||||
/* apply gain factor to normalise energy, and LPC Energy */
|
||||
|
||||
gain *= E;
|
||||
for(i=0; i<FFT_ENC/2; i++)
|
||||
{
|
||||
Pw[i] *= gain;
|
||||
}
|
||||
|
||||
if (bass_boost)
|
||||
{
|
||||
/* add 3dB to first 1 kHz to account for LP effect of PF */
|
||||
|
||||
for(i=0; i<FFT_ENC/8; i++)
|
||||
{
|
||||
Pw[i] *= 1.4*1.4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
aks_to_M2()
|
||||
|
||||
Transforms the linear prediction coefficients to spectral amplitude
|
||||
samples. This function determines A(m) from the average energy per
|
||||
band using an FFT.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void CQuantize::aks_to_M2(
|
||||
FFTR_STATE * fftr_fwd_cfg,
|
||||
float ak[], /* LPC's */
|
||||
int order,
|
||||
MODEL *model, /* sinusoidal model parameters for this frame */
|
||||
float E, /* energy term */
|
||||
float *snr, /* signal to noise ratio for this frame in dB */
|
||||
int sim_pf, /* true to simulate a post filter */
|
||||
int pf, /* true to enable actual LPC post filter */
|
||||
int bass_boost, /* enable LPC filter 0-1kHz 3dB boost */
|
||||
float beta,
|
||||
float gamma, /* LPC post filter parameters */
|
||||
std::complex<float> Aw[] /* output power spectrum */
|
||||
)
|
||||
{
|
||||
int i,m; /* loop variables */
|
||||
int am,bm; /* limits of current band */
|
||||
float r; /* no. rads/bin */
|
||||
float Em; /* energy in band */
|
||||
float Am; /* spectral amplitude sample */
|
||||
float signal, noise;
|
||||
|
||||
r = TWO_PI/(FFT_ENC);
|
||||
|
||||
/* Determine DFT of A(exp(jw)) --------------------------------------------*/
|
||||
{
|
||||
float a[FFT_ENC]; /* input to FFT for power spectrum */
|
||||
|
||||
for(i=0; i<FFT_ENC; i++)
|
||||
{
|
||||
a[i] = 0.0;
|
||||
}
|
||||
|
||||
for(i=0; i<=order; i++)
|
||||
a[i] = ak[i];
|
||||
kiss.fftr(*fftr_fwd_cfg, a, Aw);
|
||||
}
|
||||
|
||||
/* Determine power spectrum P(w) = E/(A(exp(jw))^2 ------------------------*/
|
||||
|
||||
float Pw[FFT_ENC/2];
|
||||
|
||||
for(i=0; i<FFT_ENC/2; i++)
|
||||
{
|
||||
Pw[i] = 1.0/(Aw[i].real() * Aw[i].real() + Aw[i].imag() * Aw[i].imag() + 1E-6);
|
||||
}
|
||||
|
||||
if (pf)
|
||||
lpc_post_filter(fftr_fwd_cfg, Pw, ak, order, beta, gamma, bass_boost, E);
|
||||
else
|
||||
{
|
||||
for(i=0; i<FFT_ENC/2; i++)
|
||||
{
|
||||
Pw[i] *= E;
|
||||
}
|
||||
}
|
||||
|
||||
/* Determine magnitudes from P(w) ----------------------------------------*/
|
||||
|
||||
/* when used just by decoder {A} might be all zeroes so init signal
|
||||
and noise to prevent log(0) errors */
|
||||
|
||||
signal = 1E-30;
|
||||
noise = 1E-32;
|
||||
|
||||
for(m=1; m<=model->L; m++)
|
||||
{
|
||||
am = (int)((m - 0.5)*model->Wo/r + 0.5);
|
||||
bm = (int)((m + 0.5)*model->Wo/r + 0.5);
|
||||
|
||||
// FIXME: With arm_rfft_fast_f32 we have to use this
|
||||
// otherwise sometimes a to high bm is calculated
|
||||
// which causes trouble later in the calculation
|
||||
// chain
|
||||
// it seems for some reason model->Wo is calculated somewhat too high
|
||||
if (bm>FFT_ENC/2)
|
||||
{
|
||||
bm = FFT_ENC/2;
|
||||
}
|
||||
Em = 0.0;
|
||||
|
||||
for(i=am; i<bm; i++)
|
||||
Em += Pw[i];
|
||||
Am = sqrtf(Em);
|
||||
|
||||
signal += model->A[m]*model->A[m];
|
||||
noise += (model->A[m] - Am)*(model->A[m] - Am);
|
||||
|
||||
/* This code significantly improves perf of LPC model, in
|
||||
particular when combined with phase0. The LPC spectrum tends
|
||||
to track just under the peaks of the spectral envelope, and
|
||||
just above nulls. This algorithm does the reverse to
|
||||
compensate - raising the amplitudes of spectral peaks, while
|
||||
attenuating the null. This enhances the formants, and
|
||||
supresses the energy between formants. */
|
||||
|
||||
if (sim_pf)
|
||||
{
|
||||
if (Am > model->A[m])
|
||||
Am *= 0.7;
|
||||
if (Am < model->A[m])
|
||||
Am *= 1.4;
|
||||
}
|
||||
model->A[m] = Am;
|
||||
}
|
||||
*snr = 10.0*log10f(signal/noise);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: encode_Wo()
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 22/8/2010
|
||||
|
||||
Encodes Wo using a WO_LEVELS quantiser.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
int CQuantize::encode_Wo(C2CONST *c2const, float Wo, int bits)
|
||||
{
|
||||
int index, Wo_levels = 1<<bits;
|
||||
float Wo_min = c2const->Wo_min;
|
||||
float Wo_max = c2const->Wo_max;
|
||||
float norm;
|
||||
|
||||
norm = (Wo - Wo_min)/(Wo_max - Wo_min);
|
||||
index = floorf(Wo_levels * norm + 0.5);
|
||||
if (index < 0 ) index = 0;
|
||||
if (index > (Wo_levels-1)) index = Wo_levels-1;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: decode_Wo()
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 22/8/2010
|
||||
|
||||
Decodes Wo using a WO_LEVELS quantiser.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
float CQuantize::decode_Wo(C2CONST *c2const, int index, int bits)
|
||||
{
|
||||
float Wo_min = c2const->Wo_min;
|
||||
float Wo_max = c2const->Wo_max;
|
||||
float step;
|
||||
float Wo;
|
||||
int Wo_levels = 1<<bits;
|
||||
|
||||
step = (Wo_max - Wo_min)/Wo_levels;
|
||||
Wo = Wo_min + step*(index);
|
||||
|
||||
return Wo;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: speech_to_uq_lsps()
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 22/8/2010
|
||||
|
||||
Analyse a windowed frame of time domain speech to determine LPCs
|
||||
which are the converted to LSPs for quantisation and transmission
|
||||
over the channel.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
float CQuantize::speech_to_uq_lsps(float lsp[], float ak[], float Sn[], float w[], int m_pitch, int order)
|
||||
{
|
||||
int i, roots;
|
||||
float Wn[m_pitch];
|
||||
float R[order+1];
|
||||
float e, E;
|
||||
Clpc lpc;
|
||||
|
||||
e = 0.0;
|
||||
for(i=0; i<m_pitch; i++)
|
||||
{
|
||||
Wn[i] = Sn[i]*w[i];
|
||||
e += Wn[i]*Wn[i];
|
||||
}
|
||||
|
||||
/* trap 0 energy case as LPC analysis will fail */
|
||||
|
||||
if (e == 0.0)
|
||||
{
|
||||
for(i=0; i<order; i++)
|
||||
lsp[i] = (PI/order)*(float)i;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
lpc.autocorrelate(Wn, R, m_pitch, order);
|
||||
lpc.levinson_durbin(R, ak, order);
|
||||
|
||||
E = 0.0;
|
||||
for(i=0; i<=order; i++)
|
||||
E += ak[i]*R[i];
|
||||
|
||||
/* 15 Hz BW expansion as I can't hear the difference and it may help
|
||||
help occasional fails in the LSP root finding. Important to do this
|
||||
after energy calculation to avoid -ve energy values.
|
||||
*/
|
||||
|
||||
for(i=0; i<=order; i++)
|
||||
ak[i] *= powf(0.994,(float)i);
|
||||
|
||||
roots = lpc_to_lsp(ak, order, lsp, 5, LSP_DELTA1);
|
||||
if (roots != order)
|
||||
{
|
||||
/* if root finding fails use some benign LSP values instead */
|
||||
for(i=0; i<order; i++)
|
||||
lsp[i] = (PI/order)*(float)i;
|
||||
}
|
||||
|
||||
return E;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: encode_lsps_scalar()
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 22/8/2010
|
||||
|
||||
Thirty-six bit sclar LSP quantiser. From a vector of unquantised
|
||||
(floating point) LSPs finds the quantised LSP indexes.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void CQuantize::encode_lsps_scalar(int indexes[], float lsp[], int order)
|
||||
{
|
||||
int i,k,m;
|
||||
float wt[1];
|
||||
float lsp_hz[order];
|
||||
const float *cb;
|
||||
float se;
|
||||
|
||||
/* convert from radians to Hz so we can use human readable
|
||||
frequencies */
|
||||
|
||||
for(i=0; i<order; i++)
|
||||
lsp_hz[i] = (4000.0/PI)*lsp[i];
|
||||
|
||||
/* scalar quantisers */
|
||||
|
||||
wt[0] = 1.0;
|
||||
for(i=0; i<order; i++)
|
||||
{
|
||||
k = lsp_cb[i].k;
|
||||
m = lsp_cb[i].m;
|
||||
cb = lsp_cb[i].cb;
|
||||
indexes[i] = quantise(cb, &lsp_hz[i], wt, k, m, &se);
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: decode_lsps_scalar()
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 22/8/2010
|
||||
|
||||
From a vector of quantised LSP indexes, returns the quantised
|
||||
(floating point) LSPs.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void CQuantize::decode_lsps_scalar(float lsp[], int indexes[], int order)
|
||||
{
|
||||
int i,k;
|
||||
float lsp_hz[order];
|
||||
const float *cb;
|
||||
|
||||
for(i=0; i<order; i++)
|
||||
{
|
||||
k = lsp_cb[i].k;
|
||||
cb = lsp_cb[i].cb;
|
||||
lsp_hz[i] = cb[indexes[i]*k];
|
||||
}
|
||||
|
||||
/* convert back to radians */
|
||||
|
||||
for(i=0; i<order; i++)
|
||||
lsp[i] = (PI/4000.0)*lsp_hz[i];
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: bw_expand_lsps()
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 22/8/2010
|
||||
|
||||
Applies Bandwidth Expansion (BW) to a vector of LSPs. Prevents any
|
||||
two LSPs getting too close together after quantisation. We know
|
||||
from experiment that LSP quantisation errors < 12.5Hz (25Hz step
|
||||
size) are inaudible so we use that as the minimum LSP separation.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void CQuantize::bw_expand_lsps(float lsp[], int order, float min_sep_low, float min_sep_high)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=1; i<4; i++)
|
||||
{
|
||||
|
||||
if ((lsp[i] - lsp[i-1]) < min_sep_low*(PI/4000.0))
|
||||
lsp[i] = lsp[i-1] + min_sep_low*(PI/4000.0);
|
||||
|
||||
}
|
||||
|
||||
/* As quantiser gaps increased, larger BW expansion was required
|
||||
to prevent twinkly noises. This may need more experiment for
|
||||
different quanstisers.
|
||||
*/
|
||||
|
||||
for(i=4; i<order; i++)
|
||||
{
|
||||
if (lsp[i] - lsp[i-1] < min_sep_high*(PI/4000.0))
|
||||
lsp[i] = lsp[i-1] + min_sep_high*(PI/4000.0);
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: apply_lpc_correction()
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 22/8/2010
|
||||
|
||||
Apply first harmonic LPC correction at decoder. This helps improve
|
||||
low pitch males after LPC modelling, like hts1a and morig.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
void CQuantize::apply_lpc_correction(MODEL *model)
|
||||
{
|
||||
if (model->Wo < (PI*150.0/4000))
|
||||
{
|
||||
model->A[1] *= 0.032;
|
||||
}
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: encode_energy()
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 22/8/2010
|
||||
|
||||
Encodes LPC energy using an E_LEVELS quantiser.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
int CQuantize::encode_energy(float e, int bits)
|
||||
{
|
||||
int index, e_levels = 1<<bits;
|
||||
float e_min = E_MIN_DB;
|
||||
float e_max = E_MAX_DB;
|
||||
float norm;
|
||||
|
||||
e = 10.0*log10f(e);
|
||||
norm = (e - e_min)/(e_max - e_min);
|
||||
index = floorf(e_levels * norm + 0.5);
|
||||
if (index < 0 ) index = 0;
|
||||
if (index > (e_levels-1)) index = e_levels-1;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: decode_energy()
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 22/8/2010
|
||||
|
||||
Decodes energy using a E_LEVELS quantiser.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
float CQuantize::decode_energy(int index, int bits)
|
||||
{
|
||||
float e_min = E_MIN_DB;
|
||||
float e_max = E_MAX_DB;
|
||||
float step;
|
||||
float e;
|
||||
int e_levels = 1<<bits;
|
||||
|
||||
step = (e_max - e_min)/e_levels;
|
||||
e = e_min + step*(index);
|
||||
e = exp10f(e/10.0);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: lpc_to_lsp()
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 24/2/93
|
||||
|
||||
This function converts LPC coefficients to LSP coefficients.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
int CQuantize::lpc_to_lsp(float *a, int order, float *freq, int nb, float delta)
|
||||
/* float *a lpc coefficients */
|
||||
/* int order order of LPC coefficients (10) */
|
||||
/* float *freq LSP frequencies in radians */
|
||||
/* int nb number of sub-intervals (4) */
|
||||
/* float delta grid spacing interval (0.02) */
|
||||
{
|
||||
float psuml,psumr,psumm,temp_xr,xl,xr,xm = 0;
|
||||
float temp_psumr;
|
||||
int i,j,m,flag,k;
|
||||
float *px; /* ptrs of respective P'(z) & Q'(z) */
|
||||
float *qx;
|
||||
float *p;
|
||||
float *q;
|
||||
float *pt; /* ptr used for cheb_poly_eval()
|
||||
whether P' or Q' */
|
||||
int roots=0; /* number of roots found */
|
||||
float Q[order + 1];
|
||||
float P[order + 1];
|
||||
|
||||
flag = 1;
|
||||
m = order/2; /* order of P'(z) & Q'(z) polynimials */
|
||||
|
||||
/* Allocate memory space for polynomials */
|
||||
|
||||
/* determine P'(z)'s and Q'(z)'s coefficients where
|
||||
P'(z) = P(z)/(1 + z^(-1)) and Q'(z) = Q(z)/(1-z^(-1)) */
|
||||
|
||||
px = P; /* initilaise ptrs */
|
||||
qx = Q;
|
||||
p = px;
|
||||
q = qx;
|
||||
*px++ = 1.0;
|
||||
*qx++ = 1.0;
|
||||
for(i=1; i<=m; i++)
|
||||
{
|
||||
*px++ = a[i]+a[order+1-i]-*p++;
|
||||
*qx++ = a[i]-a[order+1-i]+*q++;
|
||||
}
|
||||
px = P;
|
||||
qx = Q;
|
||||
for(i=0; i<m; i++)
|
||||
{
|
||||
*px = 2**px;
|
||||
*qx = 2**qx;
|
||||
px++;
|
||||
qx++;
|
||||
}
|
||||
px = P; /* re-initialise ptrs */
|
||||
qx = Q;
|
||||
|
||||
/* Search for a zero in P'(z) polynomial first and then alternate to Q'(z).
|
||||
Keep alternating between the two polynomials as each zero is found */
|
||||
|
||||
xr = 0; /* initialise xr to zero */
|
||||
xl = 1.0; /* start at point xl = 1 */
|
||||
|
||||
|
||||
for(j=0; j<order; j++)
|
||||
{
|
||||
if(j%2) /* determines whether P' or Q' is eval. */
|
||||
pt = qx;
|
||||
else
|
||||
pt = px;
|
||||
|
||||
psuml = cheb_poly_eva(pt,xl,order); /* evals poly. at xl */
|
||||
flag = 1;
|
||||
while(flag && (xr >= -1.0))
|
||||
{
|
||||
xr = xl - delta ; /* interval spacing */
|
||||
psumr = cheb_poly_eva(pt,xr,order);/* poly(xl-delta_x) */
|
||||
temp_psumr = psumr;
|
||||
temp_xr = xr;
|
||||
|
||||
/* if no sign change increment xr and re-evaluate
|
||||
poly(xr). Repeat til sign change. if a sign change has
|
||||
occurred the interval is bisected and then checked again
|
||||
for a sign change which determines in which interval the
|
||||
zero lies in. If there is no sign change between poly(xm)
|
||||
and poly(xl) set interval between xm and xr else set
|
||||
interval between xl and xr and repeat till root is located
|
||||
within the specified limits */
|
||||
|
||||
if(((psumr*psuml)<0.0) || (psumr == 0.0))
|
||||
{
|
||||
roots++;
|
||||
|
||||
psumm=psuml;
|
||||
for(k=0; k<=nb; k++)
|
||||
{
|
||||
xm = (xl+xr)/2; /* bisect the interval */
|
||||
psumm=cheb_poly_eva(pt,xm,order);
|
||||
if(psumm*psuml>0.)
|
||||
{
|
||||
psuml=psumm;
|
||||
xl=xm;
|
||||
}
|
||||
else
|
||||
{
|
||||
psumr=psumm;
|
||||
xr=xm;
|
||||
}
|
||||
}
|
||||
|
||||
/* once zero is found, reset initial interval to xr */
|
||||
freq[j] = (xm);
|
||||
xl = xm;
|
||||
flag = 0; /* reset flag for next search */
|
||||
}
|
||||
else
|
||||
{
|
||||
psuml=temp_psumr;
|
||||
xl=temp_xr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* convert from x domain to radians */
|
||||
|
||||
for(i=0; i<order; i++)
|
||||
{
|
||||
freq[i] = acosf(freq[i]);
|
||||
}
|
||||
|
||||
return(roots);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FUNCTION....: cheb_poly_eva()
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 24/2/93
|
||||
|
||||
This function evalutes a series of chebyshev polynomials
|
||||
|
||||
FIXME: performing memory allocation at run time is very inefficient,
|
||||
replace with stack variables of MAX_P size.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
float CQuantize::cheb_poly_eva(float *coef,float x,int order)
|
||||
/* float coef[] coefficients of the polynomial to be evaluated */
|
||||
/* float x the point where polynomial is to be evaluated */
|
||||
/* int order order of the polynomial */
|
||||
{
|
||||
int i;
|
||||
float *t,*u,*v,sum;
|
||||
float T[(order / 2) + 1];
|
||||
|
||||
/* Initialise pointers */
|
||||
|
||||
t = T; /* T[i-2] */
|
||||
*t++ = 1.0;
|
||||
u = t--; /* T[i-1] */
|
||||
*u++ = x;
|
||||
v = u--; /* T[i] */
|
||||
|
||||
/* Evaluate chebyshev series formulation using iterative approach */
|
||||
|
||||
for(i=2; i<=order/2; i++)
|
||||
*v++ = (2*x)*(*u++) - *t++; /* T[i] = 2*x*T[i-1] - T[i-2] */
|
||||
|
||||
sum=0.0; /* initialise sum to zero */
|
||||
t = T; /* reset pointer */
|
||||
|
||||
/* Evaluate polynomial and return value also free memory space */
|
||||
|
||||
for(i=0; i<=order/2; i++)
|
||||
sum+=coef[(order/2)-i]**t++;
|
||||
|
||||
return sum;
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*---------------------------------------------------------------------------*\
|
||||
|
||||
FILE........: quantise.h
|
||||
AUTHOR......: David Rowe
|
||||
DATE CREATED: 31/5/92
|
||||
|
||||
Quantisation functions for the sinusoidal coder.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License version 2.1, as
|
||||
published by the Free Software Foundation. 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 Lesser General Public License
|
||||
along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __QUANTISE__
|
||||
#define __QUANTISE__
|
||||
|
||||
#include <complex>
|
||||
|
||||
#include "qbase.h"
|
||||
|
||||
class CQuantize : public CQbase {
|
||||
public:
|
||||
void aks_to_M2(FFTR_STATE *fftr_fwd_cfg, float ak[], int order, MODEL *model, float E, float *snr, int sim_pf, int pf, int bass_boost, float beta, float gamma, std::complex<float> Aw[]);
|
||||
|
||||
int encode_Wo(C2CONST *c2const, float Wo, int bits);
|
||||
float decode_Wo(C2CONST *c2const, int index, int bits);
|
||||
void encode_lsps_scalar(int indexes[], float lsp[], int order);
|
||||
void decode_lsps_scalar(float lsp[], int indexes[], int order);
|
||||
void encode_lspds_scalar(int indexes[], float lsp[], int order);
|
||||
void decode_lspds_scalar(float lsp[], int indexes[], int order);
|
||||
|
||||
int encode_energy(float e, int bits);
|
||||
float decode_energy(int index, int bits);
|
||||
|
||||
void pack(unsigned char * bits, unsigned int *nbit, int index, unsigned int index_bits);
|
||||
void pack_natural_or_gray(unsigned char * bits, unsigned int *nbit, int index, unsigned int index_bits, unsigned int gray);
|
||||
int unpack(const unsigned char * bits, unsigned int *nbit, unsigned int index_bits);
|
||||
int unpack_natural_or_gray(const unsigned char * bits, unsigned int *nbit, unsigned int index_bits, unsigned int gray);
|
||||
|
||||
int lsp_bits(int i);
|
||||
int lspd_bits(int i);
|
||||
|
||||
void apply_lpc_correction(MODEL *model);
|
||||
float speech_to_uq_lsps(float lsp[], float ak[], float Sn[], float w[], int m_pitch, int order);
|
||||
int check_lsp_order(float lsp[], int lpc_order);
|
||||
void bw_expand_lsps(float lsp[], int order, float min_sep_low, float min_sep_high);
|
||||
|
||||
private:
|
||||
void compute_weights(const float *x, float *w, int ndim);
|
||||
int find_nearest(const float *codebook, int nb_entries, float *x, int ndim);
|
||||
void lpc_post_filter(FFTR_STATE *fftr_fwd_cfg, float Pw[], float ak[], int order, float beta, float gamma, int bass_boost, float E);
|
||||
int lpc_to_lsp (float *a, int lpcrdr, float *freq, int nb, float delta);
|
||||
float cheb_poly_eva(float *coef,float x,int order);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* Project 25 IMBE Encoder/Decoder Fixed-Point implementation
|
||||
* Developed by Pavel Yazev E-mail: pyazev@gmail.com
|
||||
* Version 1.0 (c) Copyright 2009
|
||||
*
|
||||
* This 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 3, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* The software 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; see the file COPYING. If not, write to the Free
|
||||
* Software Foundation, Inc., 51 Franklin Street, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
/*
|
||||
********************************************************************************
|
||||
*
|
||||
* GSM AMR speech codec Version 7.4.0 January 31, 2000
|
||||
*
|
||||
********************************************************************************
|
||||
*
|
||||
* File : typedefs.h
|
||||
* Description : Definition of platform independent data
|
||||
* types and constants
|
||||
*
|
||||
*
|
||||
* The following platform independent data types and corresponding
|
||||
* preprocessor (#define) constants are defined:
|
||||
*
|
||||
* defined type meaning corresponding constants
|
||||
* ----------------------------------------------------------
|
||||
* Char character (none)
|
||||
* Bool boolean true, false
|
||||
* Word8 8-bit signed minWord8, maxWord8
|
||||
* UWord8 8-bit unsigned minUWord8, maxUWord8
|
||||
* Word16 16-bit signed minWord16, maxWord16
|
||||
* UWord16 16-bit unsigned minUWord16, maxUWord16
|
||||
* Word32 32-bit signed minWord32, maxWord32
|
||||
* UWord32 32-bit unsigned minUWord32, maxUWord32
|
||||
* Float floating point minFloat, maxFloat
|
||||
*
|
||||
*
|
||||
* The following compile switches are #defined:
|
||||
*
|
||||
* PLATFORM string indicating platform progam is compiled on
|
||||
* possible values: "OSF", "PC", "SUN"
|
||||
*
|
||||
* OSF only defined if the current platform is an Alpha
|
||||
* PC only defined if the current platform is a PC
|
||||
* SUN only defined if the current platform is a Sun
|
||||
*
|
||||
* LSBFIRST is defined if the byte order on this platform is
|
||||
* "least significant byte first" -> defined on DEC Alpha
|
||||
* and PC, undefined on Sun
|
||||
*
|
||||
********************************************************************************
|
||||
*/
|
||||
#ifndef typedefs_h
|
||||
#define typedefs_h "$Id $"
|
||||
|
||||
/*
|
||||
********************************************************************************
|
||||
* INCLUDE FILES
|
||||
********************************************************************************
|
||||
*/
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define __MSDOS__
|
||||
|
||||
/*
|
||||
********************************************************************************
|
||||
* DEFINITION OF CONSTANTS
|
||||
********************************************************************************
|
||||
*/
|
||||
/*
|
||||
********* define char type
|
||||
*/
|
||||
typedef char Char;
|
||||
|
||||
/*
|
||||
********* define 8 bit signed/unsigned types & constants
|
||||
*/
|
||||
#if SCHAR_MAX == 127
|
||||
typedef signed char Word8;
|
||||
#define minWord8 SCHAR_MIN
|
||||
#define maxWord8 SCHAR_MAX
|
||||
|
||||
typedef unsigned char UWord8;
|
||||
#define minUWord8 0
|
||||
#define maxUWord8 UCHAR_MAX
|
||||
#else
|
||||
#error cannot find 8-bit type
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
********* define 16 bit signed/unsigned types & constants
|
||||
*/
|
||||
#if INT_MAX == 32767
|
||||
typedef int Word16;
|
||||
#define minWord16 INT_MIN
|
||||
#define maxWord16 INT_MAX
|
||||
typedef unsigned int UWord16;
|
||||
#define minUWord16 0
|
||||
#define maxUWord16 UINT_MAX
|
||||
#elif SHRT_MAX == 32767
|
||||
typedef short Word16;
|
||||
#define minWord16 SHRT_MIN
|
||||
#define maxWord16 SHRT_MAX
|
||||
typedef unsigned short UWord16;
|
||||
#define minUWord16 0
|
||||
#define maxUWord16 USHRT_MAX
|
||||
#else
|
||||
#error cannot find 16-bit type
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
********* define 32 bit signed/unsigned types & constants
|
||||
*/
|
||||
#if INT_MAX == 2147483647
|
||||
typedef int Word32;
|
||||
#define minWord32 INT_MIN
|
||||
#define maxWord32 INT_MAX
|
||||
typedef unsigned int UWord32;
|
||||
#define minUWord32 0
|
||||
#define maxUWord32 UINT_MAX
|
||||
#elif LONG_MAX == 2147483647
|
||||
typedef long Word32;
|
||||
#define minWord32 LONG_MIN
|
||||
#define maxWord32 LONG_MAX
|
||||
typedef unsigned long UWord32;
|
||||
#define minUWord32 0
|
||||
#define maxUWord32 ULONG_MAX
|
||||
#else
|
||||
#error cannot find 32-bit type
|
||||
#endif
|
||||
|
||||
/*
|
||||
********* define floating point type & constants
|
||||
*/
|
||||
/* use "#if 0" below if Float should be double;
|
||||
use "#if 1" below if Float should be float
|
||||
*/
|
||||
#if 0
|
||||
typedef float Float;
|
||||
#define maxFloat FLT_MAX
|
||||
#define minFloat FLT_MIN
|
||||
#else
|
||||
typedef double Float;
|
||||
#define maxFloat DBL_MAX
|
||||
#define minFloat DBL_MIN
|
||||
#endif
|
||||
|
||||
/*
|
||||
********* define complex type
|
||||
*/
|
||||
typedef struct {
|
||||
Float r; /* real part */
|
||||
Float i; /* imaginary part */
|
||||
} CPX;
|
||||
|
||||
/*
|
||||
********* define boolean type
|
||||
*/
|
||||
typedef int Bool;
|
||||
#define false 0
|
||||
#define true 1
|
||||
|
||||
/*
|
||||
********* Check current platform
|
||||
*/
|
||||
#if defined(__MSDOS__)
|
||||
#define PC
|
||||
#define PLATFORM "PC"
|
||||
#define LSBFIRST
|
||||
#elif defined(__osf__)
|
||||
#define OSF
|
||||
#define PLATFORM "OSF"
|
||||
#define LSBFIRST
|
||||
#elif defined(__sun__) || defined(__sun)
|
||||
#define SUN
|
||||
#define PLATFORM "SUN"
|
||||
#undef LSBFIRST
|
||||
#elif defined(linux) && defined(i386)
|
||||
#define PC
|
||||
#define PLATFORM "PC"
|
||||
#define LSBFIRST
|
||||
#else
|
||||
#error "can't determine architecture; adapt typedefs.h to your platform"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -43,6 +43,7 @@ public:
|
|||
std::string getP25TGListFile() const;
|
||||
bool getP25NetworkDebug() const;
|
||||
|
||||
|
||||
// The Info section
|
||||
unsigned int getRxFrequency() const;
|
||||
unsigned int getTxFrequency() const;
|
||||
|
@ -127,6 +128,7 @@ private:
|
|||
std::string m_p25TGListFile;
|
||||
bool m_p25NetworkDebug;
|
||||
|
||||
|
||||
unsigned int m_logDisplayLevel;
|
||||
unsigned int m_logFileLevel;
|
||||
std::string m_logFilePath;
|
||||
|
|
|
@ -106,7 +106,7 @@ const char* DEFAULT_INI_FILE = "/etc/P252DMR.ini";
|
|||
const char* HEADER1 = "This software is for use on amateur radio networks only,";
|
||||
const char* HEADER2 = "it is to be used for educational purposes only. Its use on";
|
||||
const char* HEADER3 = "commercial networks is strictly prohibited.";
|
||||
const char* HEADER4 = "Copyright(C) 2018 by CA6JAU, G4KLX and others";
|
||||
const char* HEADER4 = "Copyright(C) 2018 by AD8DP, CA6JAU, G4KLX and others";
|
||||
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
|
|
|
@ -49,7 +49,7 @@ const char* DEFAULT_INI_FILE = "/etc/YSF2DMR.ini";
|
|||
const char* HEADER1 = "This software is for use on amateur radio networks only,";
|
||||
const char* HEADER2 = "it is to be used for educational purposes only. Its use on";
|
||||
const char* HEADER3 = "commercial networks is strictly prohibited.";
|
||||
const char* HEADER4 = "Copyright(C) 2018,2019 by CA6JAU, EA7EE, G4KLX and others";
|
||||
const char* HEADER4 = "Copyright(C) 2018,2019 by CA6JAU, EA7EE, G4KLX, AD8DP and others";
|
||||
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
|
|
Loading…
Reference in New Issue