Initial commit
|
@ -0,0 +1,12 @@
|
|||
Debug
|
||||
Release
|
||||
x64
|
||||
*.bak
|
||||
*.obj
|
||||
*~
|
||||
*.sdf
|
||||
*.log
|
||||
*.zip
|
||||
*.exe
|
||||
*.user
|
||||
.vs
|
|
@ -0,0 +1,346 @@
|
|||
/*
|
||||
* 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(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 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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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(m_deInterData + pos);
|
||||
}
|
||||
}
|
||||
|
||||
// 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[13U] = (data[13U] & 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,114 @@
|
|||
/*
|
||||
* 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 "CRC.h"
|
||||
|
||||
#include "Utils.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
unsigned char CCRC::encodeEightBit(const unsigned char *in, unsigned int length)
|
||||
{
|
||||
assert(in != NULL);
|
||||
|
||||
unsigned char crc = 0x00U;
|
||||
|
||||
for (unsigned int i = 0U; i < length; i++) {
|
||||
crc ^= in[i];
|
||||
|
||||
for (unsigned int j = 0U; j < 8U; j++) {
|
||||
if ((crc & 0x80U) == 0x80U) {
|
||||
crc <<= 1;
|
||||
crc ^= 0x07U;
|
||||
} else {
|
||||
crc <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
bool CCRC::checkCSBK(const unsigned char *in)
|
||||
{
|
||||
unsigned short crc16 = 0U;
|
||||
|
||||
// Run through all 12 bits
|
||||
for (unsigned int a = 0; a < 12U; a++) {
|
||||
unsigned char val = in[a];
|
||||
|
||||
// Allow for the CSBK CRC mask
|
||||
if (a > 9U)
|
||||
val ^= 0xA5U;
|
||||
|
||||
for (unsigned int i = 0U; i < 8U; i++) {
|
||||
bool c15 = (crc16 >> 15 & 0x01U) == 0x01U;
|
||||
bool bit = (val >> (7 - i) & 0x01U) == 0x01U;
|
||||
crc16 <<= 1;
|
||||
if (c15 ^ bit)
|
||||
crc16 ^= 0x1021U;
|
||||
}
|
||||
}
|
||||
|
||||
return crc16 == 0x1D0FU;
|
||||
}
|
||||
|
||||
unsigned char CCRC::crc8(const unsigned char *in, unsigned int length)
|
||||
{
|
||||
unsigned int crc = 0U;
|
||||
|
||||
for (unsigned int j = 0U; j < length; j++, in++) {
|
||||
crc ^= (*in << 8);
|
||||
|
||||
for (unsigned int i = 0U; i < 8U; i++) {
|
||||
if (crc & 0x8000U)
|
||||
crc ^= (0x1070U << 3);
|
||||
crc <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return crc >> 8;
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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(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 bool checkCSBK(const unsigned char* in);
|
||||
|
||||
static unsigned char encodeEightBit(const unsigned char* in, unsigned int length);
|
||||
|
||||
static unsigned char crc8(const unsigned char* in, unsigned int length);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* 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 "CSBK.h"
|
||||
#include "BPTC19696.h"
|
||||
#include "CRC.h"
|
||||
#include "Log.h" // XXXX
|
||||
|
||||
#include "Utils.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
CCSBK::CCSBK(const unsigned char* bytes) :
|
||||
m_CSBKO(CSBKO_NONE),
|
||||
m_FID(0x00U),
|
||||
m_bsId(0U),
|
||||
m_srcId(0U),
|
||||
m_valid(false)
|
||||
{
|
||||
assert(bytes != NULL);
|
||||
|
||||
CBPTC19696 bptc;
|
||||
|
||||
unsigned char data[12U];
|
||||
bptc.decode(bytes, data);
|
||||
|
||||
m_valid = CCRC::checkCSBK(data);
|
||||
|
||||
m_CSBKO = CSBKO(data[0U] & 0x3FU);
|
||||
m_FID = data[1U];
|
||||
|
||||
if (m_CSBKO == CSBKO_BSDWNACT) {
|
||||
m_bsId = data[4U] << 16 | data[5U] << 8 | data[6U];
|
||||
m_srcId = data[7U] << 16 | data[8U] << 8 | data[9U];
|
||||
CUtils::dump("Download activate CSBK", data, 12U);
|
||||
} else {
|
||||
CUtils::dump("Unhandled CSBK type", data, 12U);
|
||||
}
|
||||
}
|
||||
|
||||
CCSBK::~CCSBK()
|
||||
{
|
||||
}
|
||||
|
||||
bool CCSBK::isValid() const
|
||||
{
|
||||
return m_valid;
|
||||
}
|
||||
|
||||
CSBKO CCSBK::getCSBKO() const
|
||||
{
|
||||
return m_CSBKO;
|
||||
}
|
||||
|
||||
unsigned char CCSBK::getFID() const
|
||||
{
|
||||
return m_FID;
|
||||
}
|
||||
|
||||
unsigned int CCSBK::getBSId() const
|
||||
{
|
||||
return m_bsId;
|
||||
}
|
||||
|
||||
unsigned int CCSBK::getSrcId() const
|
||||
{
|
||||
return m_srcId;
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* 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(CSBK_H)
|
||||
#define CSBK_H
|
||||
|
||||
#include "DMRDefines.h"
|
||||
|
||||
enum CSBKO {
|
||||
CSBKO_NONE = 0x00,
|
||||
CSBKO_UUVREQ = 0x04,
|
||||
CSBKO_UUANSRSP = 0x05,
|
||||
CSBKO_CTCSBK = 0x07,
|
||||
CSBKO_NACKRSP = 0x26,
|
||||
CSBKO_BSDWNACT = 0x38,
|
||||
CSBKO_PRECCSBK = 0x3D
|
||||
};
|
||||
|
||||
class CCSBK
|
||||
{
|
||||
public:
|
||||
CCSBK(const unsigned char* bytes);
|
||||
~CCSBK();
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
// Generic fields
|
||||
CSBKO getCSBKO() const;
|
||||
unsigned char getFID() const;
|
||||
|
||||
// For BS Dwn Act
|
||||
unsigned int getBSId() const;
|
||||
unsigned int getSrcId() const;
|
||||
|
||||
private:
|
||||
CSBKO m_CSBKO;
|
||||
unsigned char m_FID;
|
||||
unsigned int m_bsId;
|
||||
unsigned int m_srcId;
|
||||
bool m_valid;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,494 @@
|
|||
/*
|
||||
* 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 "Conf.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
const int BUFFER_SIZE = 500;
|
||||
|
||||
enum SECTION {
|
||||
SECTION_NONE,
|
||||
SECTION_GENERAL,
|
||||
SECTION_INFO,
|
||||
SECTION_LOG,
|
||||
SECTION_MODEM,
|
||||
SECTION_DSTAR,
|
||||
SECTION_DMR,
|
||||
SECTION_FUSION,
|
||||
SECTION_DSTAR_NETWORK,
|
||||
SECTION_DMR_NETWORK,
|
||||
SECTION_FUSION_NETWORK,
|
||||
SECTION_TFTSERIAL
|
||||
};
|
||||
|
||||
CConf::CConf(const std::string& file) :
|
||||
m_file(file),
|
||||
m_callsign(),
|
||||
m_timeout(120U),
|
||||
m_duplex(true),
|
||||
m_modeHang(10U),
|
||||
m_display(),
|
||||
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_logLevel(0U),
|
||||
m_logPath(),
|
||||
m_logRoot(),
|
||||
m_logDisplay(true),
|
||||
m_modemPort(),
|
||||
m_modemRXInvert(false),
|
||||
m_modemTXInvert(false),
|
||||
m_modemPTTInvert(false),
|
||||
m_modemTXDelay(100U),
|
||||
m_modemRXLevel(100U),
|
||||
m_modemTXLevel(100U),
|
||||
m_modemDebug(false),
|
||||
m_dstarEnabled(true),
|
||||
m_dstarModule("C"),
|
||||
m_dmrEnabled(true),
|
||||
m_dmrId(0U),
|
||||
m_dmrColorCode(2U),
|
||||
m_fusionEnabled(true),
|
||||
m_dstarNetworkEnabled(true),
|
||||
m_dstarGatewayAddress(),
|
||||
m_dstarGatewayPort(0U),
|
||||
m_dstarLocalPort(0U),
|
||||
m_dstarNetworkDebug(false),
|
||||
m_dmrNetworkEnabled(true),
|
||||
m_dmrNetworkAddress(),
|
||||
m_dmrNetworkPort(0U),
|
||||
m_dmrNetworkPassword(),
|
||||
m_dmrNetworkDebug(false),
|
||||
m_fusionNetworkEnabled(false),
|
||||
m_fusionNetworkAddress(),
|
||||
m_fusionNetworkPort(0U),
|
||||
m_fusionNetworkDebug(false),
|
||||
m_tftSerialPort()
|
||||
{
|
||||
}
|
||||
|
||||
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, "[General]", 9U) == 0)
|
||||
section = SECTION_GENERAL;
|
||||
else if (::strncmp(buffer, "[Info]", 6U) == 0)
|
||||
section = SECTION_INFO;
|
||||
else if (::strncmp(buffer, "[Log]", 5U) == 0)
|
||||
section = SECTION_LOG;
|
||||
else if (::strncmp(buffer, "[Modem]", 7U) == 0)
|
||||
section = SECTION_MODEM;
|
||||
else if (::strncmp(buffer, "[D-Star]", 8U) == 0)
|
||||
section = SECTION_DSTAR;
|
||||
else if (::strncmp(buffer, "[DMR]", 5U) == 0)
|
||||
section = SECTION_DMR;
|
||||
else if (::strncmp(buffer, "[System Fusion]", 15U) == 0)
|
||||
section = SECTION_FUSION;
|
||||
else if (::strncmp(buffer, "[D-Star Network]", 16U) == 0)
|
||||
section = SECTION_DSTAR_NETWORK;
|
||||
else if (::strncmp(buffer, "[DMR Network]", 13U) == 0)
|
||||
section = SECTION_DMR_NETWORK;
|
||||
else if (::strncmp(buffer, "[System Fusion Network]", 23U) == 0)
|
||||
section = SECTION_FUSION_NETWORK;
|
||||
else if (::strncmp(buffer, "[TFT Serial]", 11U) == 0)
|
||||
section = SECTION_TFTSERIAL;
|
||||
else
|
||||
section = SECTION_NONE;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
char* key = ::strtok(buffer, " \t=\r\n");
|
||||
if (key == NULL)
|
||||
continue;
|
||||
|
||||
char* value = ::strtok(NULL, "\r\n");
|
||||
if (section == SECTION_GENERAL) {
|
||||
if (::strcmp(key, "Callsign") == 0)
|
||||
m_callsign = value;
|
||||
else if (::strcmp(key, "Timeout") == 0)
|
||||
m_timeout = (unsigned int)::atoi(value);
|
||||
else if (::strcmp(key, "Duplex") == 0)
|
||||
m_duplex = ::atoi(value) == 1;
|
||||
else if (::strcmp(key, "ModeHang") == 0)
|
||||
m_modeHang = (unsigned int)::atoi(value);
|
||||
else if (::strcmp(key, "Display") == 0)
|
||||
m_display = value;
|
||||
} else 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_LOG) {
|
||||
if (::strcmp(key, "Path") == 0)
|
||||
m_logPath = value;
|
||||
else if (::strcmp(key, "Root") == 0)
|
||||
m_logRoot = value;
|
||||
else if (::strcmp(key, "Level") == 0)
|
||||
m_logLevel = (unsigned int)::atoi(value);
|
||||
else if (::strcmp(key, "Display") == 0)
|
||||
m_logDisplay = ::atoi(value) == 1;
|
||||
} else if (section == SECTION_MODEM) {
|
||||
if (::strcmp(key, "Port") == 0)
|
||||
m_modemPort = value;
|
||||
else if (::strcmp(key, "RXInvert") == 0)
|
||||
m_modemRXInvert = ::atoi(value) == 1;
|
||||
else if (::strcmp(key, "TXInvert") == 0)
|
||||
m_modemTXInvert = ::atoi(value) == 1;
|
||||
else if (::strcmp(key, "PTTInvert") == 0)
|
||||
m_modemPTTInvert = ::atoi(value) == 1;
|
||||
else if (::strcmp(key, "TXDelay") == 0)
|
||||
m_modemTXDelay = (unsigned int)::atoi(value);
|
||||
else if (::strcmp(key, "RXLevel") == 0)
|
||||
m_modemRXLevel = (unsigned int)::atoi(value);
|
||||
else if (::strcmp(key, "TXLevel") == 0)
|
||||
m_modemTXLevel = (unsigned int)::atoi(value);
|
||||
else if (::strcmp(key, "Debug") == 0)
|
||||
m_modemDebug = ::atoi(value) == 1;
|
||||
} else if (section == SECTION_DSTAR) {
|
||||
if (::strcmp(key, "Enabled") == 0)
|
||||
m_dstarEnabled = ::atoi(value) == 1;
|
||||
else if (::strcmp(key, "Module") == 0)
|
||||
m_dstarModule = value;
|
||||
} else if (section == SECTION_DMR) {
|
||||
if (::strcmp(key, "Enabled") == 0)
|
||||
m_dmrEnabled = ::atoi(value) == 1;
|
||||
else if (::strcmp(key, "Id") == 0)
|
||||
m_dmrId = (unsigned int)::atoi(value);
|
||||
else if (::strcmp(key, "ColorCode") == 0)
|
||||
m_dmrColorCode = (unsigned int)::atoi(value);
|
||||
} else if (section == SECTION_FUSION) {
|
||||
if (::strcmp(key, "Enabled") == 0)
|
||||
m_fusionEnabled = ::atoi(value) == 1;
|
||||
} else if (section == SECTION_DSTAR_NETWORK) {
|
||||
if (::strcmp(key, "Enabled") == 0)
|
||||
m_dstarNetworkEnabled = ::atoi(value) == 1;
|
||||
else if (::strcmp(key, "GatewayAddress") == 0)
|
||||
m_dstarGatewayAddress = value;
|
||||
else if (::strcmp(key, "GatewayPort") == 0)
|
||||
m_dstarGatewayPort = (unsigned int)::atoi(value);
|
||||
else if (::strcmp(key, "LocalPort") == 0)
|
||||
m_dstarLocalPort = (unsigned int)::atoi(value);
|
||||
else if (::strcmp(key, "Debug") == 0)
|
||||
m_dstarNetworkDebug = ::atoi(value) == 1;
|
||||
} else if (section == SECTION_DMR_NETWORK) {
|
||||
if (::strcmp(key, "Enabled") == 0)
|
||||
m_dmrNetworkEnabled = ::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, "Password") == 0)
|
||||
m_dmrNetworkPassword = value;
|
||||
else if (::strcmp(key, "Debug") == 0)
|
||||
m_dmrNetworkDebug = ::atoi(value) == 1;
|
||||
} else if (section == SECTION_FUSION_NETWORK) {
|
||||
if (::strcmp(key, "Enabled") == 0)
|
||||
m_fusionNetworkEnabled = ::atoi(value) == 1;
|
||||
else if (::strcmp(key, "Address") == 0)
|
||||
m_fusionNetworkAddress = value;
|
||||
else if (::strcmp(key, "Port") == 0)
|
||||
m_fusionNetworkPort = (unsigned int)::atoi(value);
|
||||
else if (::strcmp(key, "Debug") == 0)
|
||||
m_fusionNetworkDebug = ::atoi(value) == 1;
|
||||
} else if (section == SECTION_TFTSERIAL) {
|
||||
if (::strcmp(key, "Port") == 0)
|
||||
m_tftSerialPort = value;
|
||||
}
|
||||
}
|
||||
|
||||
::fclose(fp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string CConf::getCallsign() const
|
||||
{
|
||||
return m_callsign;
|
||||
}
|
||||
|
||||
unsigned int CConf::getTimeout() const
|
||||
{
|
||||
return m_timeout;
|
||||
}
|
||||
|
||||
bool CConf::getDuplex() const
|
||||
{
|
||||
return m_duplex;
|
||||
}
|
||||
|
||||
unsigned int CConf::getModeHang() const
|
||||
{
|
||||
return m_modeHang;
|
||||
}
|
||||
|
||||
std::string CConf::getDisplay() const
|
||||
{
|
||||
return m_display;
|
||||
}
|
||||
|
||||
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::getLogLevel() const
|
||||
{
|
||||
return m_logLevel;
|
||||
}
|
||||
|
||||
std::string CConf::getLogPath() const
|
||||
{
|
||||
return m_logPath;
|
||||
}
|
||||
|
||||
std::string CConf::getLogRoot() const
|
||||
{
|
||||
return m_logRoot;
|
||||
}
|
||||
|
||||
bool CConf::getLogDisplay() const
|
||||
{
|
||||
return m_logDisplay;
|
||||
}
|
||||
|
||||
std::string CConf::getModemPort() const
|
||||
{
|
||||
return m_modemPort;
|
||||
}
|
||||
|
||||
bool CConf::getModemRXInvert() const
|
||||
{
|
||||
return m_modemRXInvert;
|
||||
}
|
||||
|
||||
bool CConf::getModemTXInvert() const
|
||||
{
|
||||
return m_modemTXInvert;
|
||||
}
|
||||
|
||||
bool CConf::getModemPTTInvert() const
|
||||
{
|
||||
return m_modemPTTInvert;
|
||||
}
|
||||
|
||||
unsigned int CConf::getModemTXDelay() const
|
||||
{
|
||||
return m_modemTXDelay;
|
||||
}
|
||||
|
||||
unsigned int CConf::getModemRXLevel() const
|
||||
{
|
||||
return m_modemRXLevel;
|
||||
}
|
||||
|
||||
unsigned int CConf::getModemTXLevel() const
|
||||
{
|
||||
return m_modemTXLevel;
|
||||
}
|
||||
|
||||
bool CConf::getModemDebug() const
|
||||
{
|
||||
return m_modemDebug;
|
||||
}
|
||||
|
||||
bool CConf::getDStarEnabled() const
|
||||
{
|
||||
return m_dstarEnabled;
|
||||
}
|
||||
|
||||
std::string CConf::getDStarModule() const
|
||||
{
|
||||
return m_dstarModule;
|
||||
}
|
||||
|
||||
bool CConf::getDMREnabled() const
|
||||
{
|
||||
return m_dmrEnabled;
|
||||
}
|
||||
|
||||
unsigned int CConf::getDMRId() const
|
||||
{
|
||||
return m_dmrId;
|
||||
}
|
||||
|
||||
unsigned int CConf::getDMRColorCode() const
|
||||
{
|
||||
return m_dmrColorCode;
|
||||
}
|
||||
|
||||
bool CConf::getFusionEnabled() const
|
||||
{
|
||||
return m_fusionEnabled;
|
||||
}
|
||||
|
||||
bool CConf::getDStarNetworkEnabled() const
|
||||
{
|
||||
return m_dstarNetworkEnabled;
|
||||
}
|
||||
|
||||
std::string CConf::getDStarGatewayAddress() const
|
||||
{
|
||||
return m_dstarGatewayAddress;
|
||||
}
|
||||
|
||||
unsigned int CConf::getDStarGatewayPort() const
|
||||
{
|
||||
return m_dstarGatewayPort;
|
||||
}
|
||||
|
||||
unsigned int CConf::getDStarLocalPort() const
|
||||
{
|
||||
return m_dstarLocalPort;
|
||||
}
|
||||
|
||||
bool CConf::getDStarNetworkDebug() const
|
||||
{
|
||||
return m_dstarNetworkDebug;
|
||||
}
|
||||
|
||||
bool CConf::getDMRNetworkEnabled() const
|
||||
{
|
||||
return m_dmrNetworkEnabled;
|
||||
}
|
||||
|
||||
std::string CConf::getDMRNetworkAddress() const
|
||||
{
|
||||
return m_dmrNetworkAddress;
|
||||
}
|
||||
|
||||
unsigned int CConf::getDMRNetworkPort() const
|
||||
{
|
||||
return m_dmrNetworkPort;
|
||||
}
|
||||
|
||||
std::string CConf::getDMRNetworkPassword() const
|
||||
{
|
||||
return m_dmrNetworkPassword;
|
||||
}
|
||||
|
||||
bool CConf::getDMRNetworkDebug() const
|
||||
{
|
||||
return m_dmrNetworkDebug;
|
||||
}
|
||||
|
||||
bool CConf::getFusionNetworkEnabled() const
|
||||
{
|
||||
return m_fusionNetworkEnabled;
|
||||
}
|
||||
|
||||
std::string CConf::getFusionNetworkAddress() const
|
||||
{
|
||||
return m_fusionNetworkAddress;
|
||||
}
|
||||
|
||||
unsigned int CConf::getFusionNetworkPort() const
|
||||
{
|
||||
return m_fusionNetworkPort;
|
||||
}
|
||||
|
||||
bool CConf::getFusionNetworkDebug() const
|
||||
{
|
||||
return m_fusionNetworkDebug;
|
||||
}
|
||||
|
||||
std::string CConf::getTFTSerialPort() const
|
||||
{
|
||||
return m_tftSerialPort;
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* 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(CONF_H)
|
||||
#define CONF_H
|
||||
|
||||
#include <string>
|
||||
|
||||
class CConf
|
||||
{
|
||||
public:
|
||||
CConf(const std::string& file);
|
||||
~CConf();
|
||||
|
||||
bool read();
|
||||
|
||||
// The General section
|
||||
std::string getCallsign() const;
|
||||
unsigned int getTimeout() const;
|
||||
bool getDuplex() const;
|
||||
unsigned int getModeHang() const;
|
||||
std::string getDisplay() 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 Log section
|
||||
std::string getLogPath() const;
|
||||
std::string getLogRoot() const;
|
||||
unsigned int getLogLevel() const;
|
||||
bool getLogDisplay() const;
|
||||
|
||||
// The Modem section
|
||||
std::string getModemPort() const;
|
||||
bool getModemRXInvert() const;
|
||||
bool getModemTXInvert() const;
|
||||
bool getModemPTTInvert() const;
|
||||
unsigned int getModemTXDelay() const;
|
||||
unsigned int getModemRXLevel() const;
|
||||
unsigned int getModemTXLevel() const;
|
||||
bool getModemDebug() const;
|
||||
|
||||
// The D-Star section
|
||||
bool getDStarEnabled() const;
|
||||
std::string getDStarModule() const;
|
||||
|
||||
// The DMR section
|
||||
bool getDMREnabled() const;
|
||||
unsigned int getDMRId() const;
|
||||
unsigned int getDMRColorCode() const;
|
||||
|
||||
// The System Fusion section
|
||||
bool getFusionEnabled() const;
|
||||
|
||||
// The D-Star Network section
|
||||
bool getDStarNetworkEnabled() const;
|
||||
std::string getDStarGatewayAddress() const;
|
||||
unsigned int getDStarGatewayPort() const;
|
||||
unsigned int getDStarLocalPort() const;
|
||||
bool getDStarNetworkDebug() const;
|
||||
|
||||
// The DMR Network section
|
||||
bool getDMRNetworkEnabled() const;
|
||||
std::string getDMRNetworkAddress() const;
|
||||
unsigned int getDMRNetworkPort() const;
|
||||
std::string getDMRNetworkPassword() const;
|
||||
bool getDMRNetworkDebug() const;
|
||||
|
||||
// The System Fusion Network section
|
||||
bool getFusionNetworkEnabled() const;
|
||||
std::string getFusionNetworkAddress() const;
|
||||
unsigned int getFusionNetworkPort() const;
|
||||
bool getFusionNetworkDebug() const;
|
||||
|
||||
// The TFTSERIAL section
|
||||
std::string getTFTSerialPort() const;
|
||||
|
||||
private:
|
||||
std::string m_file;
|
||||
std::string m_callsign;
|
||||
unsigned int m_timeout;
|
||||
bool m_duplex;
|
||||
unsigned int m_modeHang;
|
||||
std::string m_display;
|
||||
|
||||
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_logLevel;
|
||||
std::string m_logPath;
|
||||
std::string m_logRoot;
|
||||
bool m_logDisplay;
|
||||
|
||||
std::string m_modemPort;
|
||||
bool m_modemRXInvert;
|
||||
bool m_modemTXInvert;
|
||||
bool m_modemPTTInvert;
|
||||
unsigned int m_modemTXDelay;
|
||||
unsigned int m_modemRXLevel;
|
||||
unsigned int m_modemTXLevel;
|
||||
bool m_modemDebug;
|
||||
|
||||
bool m_dstarEnabled;
|
||||
std::string m_dstarModule;
|
||||
|
||||
bool m_dmrEnabled;
|
||||
unsigned int m_dmrId;
|
||||
unsigned int m_dmrColorCode;
|
||||
|
||||
bool m_fusionEnabled;
|
||||
|
||||
bool m_dstarNetworkEnabled;
|
||||
std::string m_dstarGatewayAddress;
|
||||
unsigned int m_dstarGatewayPort;
|
||||
unsigned int m_dstarLocalPort;
|
||||
bool m_dstarNetworkDebug;
|
||||
|
||||
bool m_dmrNetworkEnabled;
|
||||
std::string m_dmrNetworkAddress;
|
||||
unsigned int m_dmrNetworkPort;
|
||||
std::string m_dmrNetworkPassword;
|
||||
bool m_dmrNetworkDebug;
|
||||
|
||||
bool m_fusionNetworkEnabled;
|
||||
unsigned int m_fusionNetworkPort;
|
||||
std::string m_fusionNetworkAddress;
|
||||
bool m_fusionNetworkDebug;
|
||||
|
||||
std::string m_tftSerialPort;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Copyright (C) 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 "DMRControl.h"
|
||||
#include "Defines.h"
|
||||
#include "CSBK.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
CDMRControl::CDMRControl(unsigned int id, unsigned int colorCode, unsigned int timeout, CModem* modem, CHomebrewDMRIPSC* network, IDisplay* display) :
|
||||
m_id(id),
|
||||
m_colorCode(colorCode),
|
||||
m_modem(modem),
|
||||
m_network(network),
|
||||
m_slot1(1U, timeout),
|
||||
m_slot2(2U, timeout)
|
||||
{
|
||||
assert(modem != NULL);
|
||||
assert(display != NULL);
|
||||
|
||||
CDMRSlot::init(colorCode, modem, network, display);
|
||||
}
|
||||
|
||||
CDMRControl::~CDMRControl()
|
||||
{
|
||||
}
|
||||
|
||||
bool CDMRControl::processWakeup(const unsigned char* data)
|
||||
{
|
||||
// Wakeups always come in on slot 1
|
||||
if (data[0U] != TAG_DATA || data[1U] != (DMR_IDLE_RX | DMR_SYNC_DATA | DT_CSBK))
|
||||
return false;
|
||||
|
||||
CCSBK csbk(data + 2U);
|
||||
|
||||
CSBKO csbko = csbk.getCSBKO();
|
||||
if (csbko != CSBKO_BSDWNACT)
|
||||
return false;
|
||||
|
||||
unsigned int bsId = csbk.getBSId();
|
||||
if (bsId == 0xFFFFFFU) {
|
||||
LogMessage("CSBK BS_Dwn_Act for any received from %u", csbk.getSrcId());
|
||||
return true;
|
||||
} else if (bsId == m_id) {
|
||||
LogMessage("CSBK BS_Dwn_Act for %u received from %u", bsId, csbk.getSrcId());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CDMRControl::writeModemSlot1(unsigned char *data)
|
||||
{
|
||||
m_slot1.writeModem(data);
|
||||
}
|
||||
|
||||
void CDMRControl::writeModemSlot2(unsigned char *data)
|
||||
{
|
||||
m_slot2.writeModem(data);
|
||||
}
|
||||
|
||||
unsigned int CDMRControl::readModemSlot1(unsigned char *data)
|
||||
{
|
||||
return m_slot1.readModem(data);
|
||||
}
|
||||
|
||||
unsigned int CDMRControl::readModemSlot2(unsigned char *data)
|
||||
{
|
||||
return m_slot2.readModem(data);
|
||||
}
|
||||
|
||||
void CDMRControl::clock(unsigned int ms)
|
||||
{
|
||||
if (m_network != NULL) {
|
||||
CDMRData data;
|
||||
bool ret = m_network->read(data);
|
||||
if (ret) {
|
||||
unsigned int slotNo = data.getSlotNo();
|
||||
switch (slotNo) {
|
||||
case 1U: m_slot1.writeNetwork(data); break;
|
||||
case 2U: m_slot2.writeNetwork(data); break;
|
||||
default: LogError("Invalid slot no %u", slotNo); break;
|
||||
}
|
||||
}
|
||||
|
||||
m_network->clock(ms);
|
||||
}
|
||||
|
||||
m_slot1.clock(ms);
|
||||
m_slot2.clock(ms);
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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(DMRControl_H)
|
||||
#define DMRControl_H
|
||||
|
||||
#include "HomebrewDMRIPSC.h"
|
||||
#include "Display.h"
|
||||
#include "DMRSlot.h"
|
||||
#include "DMRData.h"
|
||||
#include "Modem.h"
|
||||
|
||||
|
||||
class CDMRControl {
|
||||
public:
|
||||
CDMRControl(unsigned int id, unsigned int colorCode, unsigned int timeout, CModem* modem, CHomebrewDMRIPSC* network, IDisplay* display);
|
||||
~CDMRControl();
|
||||
|
||||
bool processWakeup(const unsigned char* data);
|
||||
|
||||
void writeModemSlot1(unsigned char* data);
|
||||
void writeModemSlot2(unsigned char* data);
|
||||
|
||||
unsigned int readModemSlot1(unsigned char* data);
|
||||
unsigned int readModemSlot2(unsigned char* data);
|
||||
|
||||
void clock(unsigned int ms);
|
||||
|
||||
private:
|
||||
unsigned int m_id;
|
||||
unsigned int m_colorCode;
|
||||
CModem* m_modem;
|
||||
CHomebrewDMRIPSC* m_network;
|
||||
CDMRSlot m_slot1;
|
||||
CDMRSlot m_slot2;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* Copyright (C) 2015 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_n(data.m_n)
|
||||
{
|
||||
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_n(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_n = data.m_n;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
unsigned char CDMRData::getN() const
|
||||
{
|
||||
return m_n;
|
||||
}
|
||||
|
||||
void CDMRData::setN(unsigned char n)
|
||||
{
|
||||
m_n = n;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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; 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);
|
||||
|
||||
void setData(const unsigned char* buffer);
|
||||
unsigned int getData(unsigned char* buffer) 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;
|
||||
unsigned char m_n;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
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 IDLE_DATA[] =
|
||||
{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};
|
||||
|
||||
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 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_IDLE = 0x09U;
|
||||
|
||||
// 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 FID_ETSI = 0U;
|
||||
const unsigned char FID_DMRA = 16U;
|
||||
|
||||
enum FLCO {
|
||||
FLCO_GROUP = 0,
|
||||
FLCO_USER_USER = 3
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,718 @@
|
|||
/*
|
||||
* Copyright (C) 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 "SlotType.h"
|
||||
#include "ShortLC.h"
|
||||
#include "DMRSlot.h"
|
||||
#include "Defines.h"
|
||||
#include "DMRSync.h"
|
||||
#include "FullLC.h"
|
||||
#include "CSBK.h"
|
||||
#include "Utils.h"
|
||||
#include "EMB.h"
|
||||
#include "CRC.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <ctime>
|
||||
|
||||
unsigned int CDMRSlot::m_colorCode = 0U;
|
||||
CModem* CDMRSlot::m_modem = NULL;
|
||||
CHomebrewDMRIPSC* CDMRSlot::m_network = NULL;
|
||||
IDisplay* CDMRSlot::m_display = NULL;
|
||||
|
||||
unsigned char* CDMRSlot::m_idle = NULL;
|
||||
|
||||
FLCO CDMRSlot::m_flco1;
|
||||
unsigned char CDMRSlot::m_id1 = 0U;
|
||||
FLCO CDMRSlot::m_flco2;
|
||||
unsigned char CDMRSlot::m_id2 = 0U;
|
||||
|
||||
// #define DUMP_DMR
|
||||
|
||||
CDMRSlot::CDMRSlot(unsigned int slotNo, unsigned int timeout) :
|
||||
m_slotNo(slotNo),
|
||||
m_radioQueue(1000U),
|
||||
m_networkQueue(100U),
|
||||
m_state(SS_LISTENING),
|
||||
m_embeddedLC(),
|
||||
m_lc(NULL),
|
||||
m_seqNo(0U),
|
||||
m_n(0U),
|
||||
m_playoutTimer(1000U, 0U, 500U),
|
||||
m_networkWatchdog(1000U, 2U),
|
||||
m_timeoutTimer(1000U, timeout),
|
||||
m_fp(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
CDMRSlot::~CDMRSlot()
|
||||
{
|
||||
}
|
||||
|
||||
void CDMRSlot::writeModem(unsigned char *data)
|
||||
{
|
||||
if (data[0U] == TAG_LOST && m_state == SS_RELAYING_RF) {
|
||||
LogMessage("DMR Slot %u, transmission lost", m_slotNo);
|
||||
writeEndOfTransmission();
|
||||
return;
|
||||
}
|
||||
|
||||
if (data[0U] == TAG_LOST && m_state == SS_LATE_ENTRY) {
|
||||
m_state = SS_LISTENING;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_state == SS_RELAYING_NETWORK)
|
||||
return;
|
||||
|
||||
bool dataSync = (data[1U] & DMR_SYNC_DATA) == DMR_SYNC_DATA;
|
||||
bool audioSync = (data[1U] & DMR_SYNC_AUDIO) == DMR_SYNC_AUDIO;
|
||||
|
||||
if (dataSync) {
|
||||
CSlotType slotType;
|
||||
slotType.putData(data + 2U);
|
||||
|
||||
unsigned char colorCode = slotType.getColorCode();
|
||||
unsigned char dataType = slotType.getDataType();
|
||||
|
||||
if (colorCode != m_colorCode)
|
||||
return;
|
||||
|
||||
if (dataType == DT_VOICE_LC_HEADER) {
|
||||
if (m_state != SS_RELAYING_RF) {
|
||||
CFullLC fullLC;
|
||||
m_lc = fullLC.decode(data + 2U, DT_VOICE_LC_HEADER);
|
||||
if (m_lc == NULL) {
|
||||
LogMessage("DMR Slot %u: unable to decode the LC", m_slotNo);
|
||||
return;
|
||||
}
|
||||
|
||||
// Regenerate the LC
|
||||
fullLC.encode(*m_lc, data + 2U, DT_VOICE_LC_HEADER);
|
||||
|
||||
// Regenerate the Slot Type
|
||||
slotType.getData(data + 2U);
|
||||
|
||||
// Convert the Data Sync to be from the BS
|
||||
CDMRSync sync;
|
||||
sync.addSync(data + 2U, DST_BS_DATA);
|
||||
|
||||
data[0U] = TAG_DATA;
|
||||
data[1U] = 0x00U;
|
||||
m_n = 0U;
|
||||
|
||||
m_networkWatchdog.stop();
|
||||
m_timeoutTimer.start();
|
||||
|
||||
m_seqNo = 0U;
|
||||
|
||||
for (unsigned i = 0U; i < 3U; i++) {
|
||||
writeNetwork(data, DT_VOICE_LC_HEADER);
|
||||
writeRadioQueue(data);
|
||||
}
|
||||
|
||||
m_state = SS_RELAYING_RF;
|
||||
setShortLC(m_slotNo, m_lc->getDstId(), m_lc->getFLCO());
|
||||
|
||||
m_display->writeDMR(m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP, m_lc->getDstId());
|
||||
|
||||
LogMessage("DMR Slot %u, received RF header from %u to %s%u", m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP ? "TG " : "", m_lc->getDstId());
|
||||
}
|
||||
} else if (dataType == DT_VOICE_PI_HEADER) {
|
||||
if (m_state == SS_RELAYING_RF) {
|
||||
// Regenerate the Slot Type
|
||||
slotType.getData(data + 2U);
|
||||
|
||||
// Convert the Data Sync to be from the BS
|
||||
CDMRSync sync;
|
||||
sync.addSync(data + 2U, DST_BS_DATA);
|
||||
|
||||
data[0U] = TAG_DATA;
|
||||
data[1U] = 0x00U;
|
||||
m_n = 0U;
|
||||
|
||||
writeNetwork(data, DT_VOICE_PI_HEADER);
|
||||
writeRadioQueue(data);
|
||||
|
||||
LogMessage("DMR Slot %u, received PI header", m_slotNo);
|
||||
} else {
|
||||
// Should save the PI header for after we have a valid LC
|
||||
}
|
||||
} else {
|
||||
// Ignore wakeup CSBKs
|
||||
if (dataType == DT_CSBK) {
|
||||
CCSBK csbk(data + 2U);
|
||||
CSBKO csbko = csbk.getCSBKO();
|
||||
if (csbko == CSBKO_BSDWNACT)
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_state == SS_RELAYING_RF) {
|
||||
unsigned char end[DMR_FRAME_LENGTH_BYTES + 2U];
|
||||
|
||||
// Generate the LC
|
||||
CFullLC fullLC;
|
||||
fullLC.encode(*m_lc, end + 2U, DT_TERMINATOR_WITH_LC);
|
||||
|
||||
// Generate the Slot Type
|
||||
CSlotType slotType;
|
||||
slotType.setColorCode(m_colorCode);
|
||||
slotType.setDataType(DT_TERMINATOR_WITH_LC);
|
||||
slotType.getData(end + 2U);
|
||||
|
||||
// Set the Data Sync to be from the BS
|
||||
CDMRSync sync;
|
||||
sync.addSync(end + 2U, DST_BS_DATA);
|
||||
|
||||
end[0U] = TAG_EOT;
|
||||
end[1U] = 0x00U;
|
||||
|
||||
writeNetwork(end, DT_TERMINATOR_WITH_LC);
|
||||
writeRadioQueue(end);
|
||||
|
||||
LogMessage("DMR Slot %u, received RF end of transmission", m_slotNo);
|
||||
|
||||
// 480ms of idle to space things out
|
||||
for (unsigned int i = 0U; i < 8U; i++)
|
||||
writeRadioQueue(m_idle);
|
||||
|
||||
writeEndOfTransmission();
|
||||
|
||||
if (dataType == DT_TERMINATOR_WITH_LC)
|
||||
return;
|
||||
}
|
||||
|
||||
// Regenerate the Slot Type
|
||||
slotType.getData(data + 2U);
|
||||
|
||||
// Convert the Data Sync to be from the BS
|
||||
CDMRSync sync;
|
||||
sync.addSync(data + 2U, DST_BS_DATA);
|
||||
|
||||
data[0U] = TAG_DATA;
|
||||
data[1U] = 0x00U;
|
||||
|
||||
writeNetwork(data, dataType);
|
||||
writeRadioQueue(data);
|
||||
}
|
||||
} else if (audioSync) {
|
||||
if (m_state == SS_RELAYING_RF) {
|
||||
// Convert the Audio Sync to be from the BS
|
||||
CDMRSync sync;
|
||||
sync.addSync(data + 2U, DST_BS_AUDIO);
|
||||
|
||||
unsigned char fid = m_lc->getFID();
|
||||
if (fid == FID_ETSI || fid == FID_DMRA)
|
||||
; // AMBE FEC
|
||||
|
||||
data[0U] = TAG_DATA;
|
||||
data[1U] = 0x00U;
|
||||
m_n = 0U;
|
||||
|
||||
writeRadioQueue(data);
|
||||
writeNetwork(data, DT_VOICE_SYNC);
|
||||
} else if (m_state == SS_LISTENING) {
|
||||
m_state = SS_LATE_ENTRY;
|
||||
}
|
||||
} else {
|
||||
if (m_state == SS_RELAYING_RF) {
|
||||
// Regenerate the EMB
|
||||
CEMB emb;
|
||||
emb.putData(data + 2U);
|
||||
emb.setColorCode(m_colorCode);
|
||||
emb.getData(data + 2U);
|
||||
|
||||
unsigned char fid = m_lc->getFID();
|
||||
if (fid == FID_ETSI || fid == FID_DMRA)
|
||||
; // AMBE FEC
|
||||
|
||||
data[0U] = TAG_DATA;
|
||||
data[1U] = 0x00U;
|
||||
m_n++;
|
||||
|
||||
writeRadioQueue(data);
|
||||
writeNetwork(data, DT_VOICE);
|
||||
} else if (m_state == SS_LATE_ENTRY) {
|
||||
// If we haven't received an LC yet, then be strict on the color code
|
||||
CEMB emb;
|
||||
emb.putData(data + 2U);
|
||||
unsigned char colorCode = emb.getColorCode();
|
||||
if (colorCode != m_colorCode)
|
||||
return;
|
||||
|
||||
m_lc = m_embeddedLC.addData(data + 2U, emb.getLCSS());
|
||||
if (m_lc != NULL) {
|
||||
// Create a dummy start frame to replace the received frame
|
||||
unsigned char start[DMR_FRAME_LENGTH_BYTES + 2U];
|
||||
|
||||
CDMRSync sync;
|
||||
sync.addSync(start + 2U, DST_BS_DATA);
|
||||
|
||||
CFullLC fullLC;
|
||||
fullLC.encode(*m_lc, start + 2U, DT_VOICE_LC_HEADER);
|
||||
|
||||
CSlotType slotType;
|
||||
slotType.setColorCode(m_colorCode);
|
||||
slotType.setDataType(DT_VOICE_LC_HEADER);
|
||||
slotType.getData(start + 2U);
|
||||
|
||||
start[0U] = TAG_DATA;
|
||||
start[1U] = 0x00U;
|
||||
m_n = 0U;
|
||||
|
||||
m_networkWatchdog.stop();
|
||||
m_timeoutTimer.start();
|
||||
|
||||
m_seqNo = 0U;
|
||||
|
||||
for (unsigned int i = 0U; i < 3U; i++) {
|
||||
writeNetwork(start, DT_VOICE_LC_HEADER);
|
||||
writeRadioQueue(start);
|
||||
}
|
||||
|
||||
// Send the original audio frame out
|
||||
unsigned char fid = m_lc->getFID();
|
||||
if (fid == FID_ETSI || fid == FID_DMRA)
|
||||
; // AMBE FEC
|
||||
|
||||
data[0U] = TAG_DATA;
|
||||
data[1U] = 0x00U;
|
||||
m_n++;
|
||||
|
||||
writeRadioQueue(data);
|
||||
writeNetwork(data, DT_VOICE);
|
||||
|
||||
m_state = SS_RELAYING_RF;
|
||||
|
||||
setShortLC(m_slotNo, m_lc->getDstId(), m_lc->getFLCO());
|
||||
|
||||
m_display->writeDMR(m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP, m_lc->getDstId());
|
||||
|
||||
LogMessage("DMR Slot %u, received RF late entry from %u to %s%u", m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP ? "TG " : "", m_lc->getDstId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int CDMRSlot::readModem(unsigned char* data)
|
||||
{
|
||||
if (m_radioQueue.isEmpty())
|
||||
return 0U;
|
||||
|
||||
unsigned char len = 0U;
|
||||
m_radioQueue.getData(&len, 1U);
|
||||
|
||||
m_radioQueue.getData(data, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void CDMRSlot::writeEndOfTransmission()
|
||||
{
|
||||
m_state = SS_LISTENING;
|
||||
|
||||
setShortLC(m_slotNo, 0U);
|
||||
|
||||
m_display->clearDMR(m_slotNo);
|
||||
|
||||
m_networkWatchdog.stop();
|
||||
m_timeoutTimer.stop();
|
||||
|
||||
delete m_lc;
|
||||
m_lc = NULL;
|
||||
}
|
||||
|
||||
void CDMRSlot::writeNetwork(const CDMRData& dmrData)
|
||||
{
|
||||
if (m_state == SS_RELAYING_RF || m_state == SS_LATE_ENTRY)
|
||||
return;
|
||||
|
||||
m_networkWatchdog.start();
|
||||
|
||||
unsigned char dataType = dmrData.getDataType();
|
||||
|
||||
unsigned char data[DMR_FRAME_LENGTH_BYTES + 2U];
|
||||
dmrData.getData(data + 2U);
|
||||
|
||||
if (dataType == DT_VOICE_LC_HEADER) {
|
||||
if (m_state != SS_RELAYING_NETWORK) {
|
||||
CFullLC fullLC;
|
||||
m_lc = fullLC.decode(data + 2U, DT_VOICE_LC_HEADER);
|
||||
if (m_lc == NULL)
|
||||
m_lc = new CLC(dmrData.getFLCO(), dmrData.getSrcId(), dmrData.getDstId());
|
||||
|
||||
// Regenerate the LC
|
||||
fullLC.encode(*m_lc, data + 2U, DT_VOICE_LC_HEADER);
|
||||
|
||||
// Regenerate the Slot Type
|
||||
CSlotType slotType;
|
||||
slotType.setColorCode(m_colorCode);
|
||||
slotType.setDataType(DT_VOICE_LC_HEADER);
|
||||
slotType.getData(data + 2U);
|
||||
|
||||
// Convert the Data Sync to be from the BS
|
||||
CDMRSync sync;
|
||||
sync.addSync(data + 2U, DST_BS_DATA);
|
||||
|
||||
data[0U] = TAG_DATA;
|
||||
data[1U] = 0x00U;
|
||||
|
||||
m_playoutTimer.start();
|
||||
m_timeoutTimer.start();
|
||||
|
||||
for (unsigned int i = 0U; i < 3U; i++)
|
||||
writeNetworkQueue(data);
|
||||
|
||||
m_state = SS_RELAYING_NETWORK;
|
||||
|
||||
setShortLC(m_slotNo, m_lc->getDstId(), m_lc->getFLCO());
|
||||
|
||||
m_display->writeDMR(m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP, m_lc->getDstId());
|
||||
|
||||
#if defined(DUMP_DMR)
|
||||
openFile();
|
||||
writeFile(data);
|
||||
#endif
|
||||
LogMessage("DMR Slot %u, received network header from %u to %s%u", m_slotNo, m_lc->getSrcId(), m_lc->getFLCO() == FLCO_GROUP ? "TG " : "", m_lc->getDstId());
|
||||
}
|
||||
} else if (dataType == DT_VOICE_PI_HEADER) {
|
||||
if (m_state != SS_RELAYING_NETWORK)
|
||||
return;
|
||||
|
||||
// Regenerate the Slot Type
|
||||
CSlotType slotType;
|
||||
slotType.setColorCode(m_colorCode);
|
||||
slotType.setDataType(DT_VOICE_PI_HEADER);
|
||||
slotType.getData(data + 2U);
|
||||
|
||||
// Convert the Data Sync to be from the BS
|
||||
CDMRSync sync;
|
||||
sync.addSync(data + 2U, DST_BS_DATA);
|
||||
|
||||
data[0U] = TAG_DATA;
|
||||
data[1U] = 0x00U;
|
||||
|
||||
writeNetworkQueue(data);
|
||||
|
||||
#if defined(DUMP_DMR)
|
||||
writeFile(data);
|
||||
#endif
|
||||
} else if (dataType == DT_TERMINATOR_WITH_LC) {
|
||||
if (m_state != SS_RELAYING_NETWORK)
|
||||
return;
|
||||
|
||||
// Regenerate the LC
|
||||
CFullLC fullLC;
|
||||
fullLC.encode(*m_lc, data + 2U, DT_TERMINATOR_WITH_LC);
|
||||
|
||||
// Regenerate the Slot Type
|
||||
CSlotType slotType;
|
||||
slotType.setColorCode(m_colorCode);
|
||||
slotType.setDataType(DT_TERMINATOR_WITH_LC);
|
||||
slotType.getData(data + 2U);
|
||||
|
||||
// Convert the Data Sync to be from the BS
|
||||
CDMRSync sync;
|
||||
sync.addSync(data + 2U, DST_BS_DATA);
|
||||
|
||||
data[0U] = TAG_EOT;
|
||||
data[1U] = 0x00U;
|
||||
|
||||
writeNetworkQueue(data);
|
||||
writeEndOfTransmission();
|
||||
|
||||
#if defined(DUMP_DMR)
|
||||
writeFile(data);
|
||||
closeFile();
|
||||
#endif
|
||||
LogMessage("DMR Slot %u, received network end of transmission", m_slotNo);
|
||||
} else if (dataType == DT_VOICE_SYNC) {
|
||||
if (m_state != SS_RELAYING_NETWORK)
|
||||
return;
|
||||
|
||||
// Convert the Audio Sync to be from the BS
|
||||
CDMRSync sync;
|
||||
sync.addSync(data + 2U, DST_BS_AUDIO);
|
||||
|
||||
unsigned char fid = m_lc->getFID();
|
||||
if (fid == FID_ETSI || fid == FID_DMRA)
|
||||
; // AMBE FEC
|
||||
|
||||
data[0U] = TAG_DATA;
|
||||
data[1U] = 0x00U;
|
||||
|
||||
writeNetworkQueue(data);
|
||||
|
||||
#if defined(DUMP_DMR)
|
||||
writeFile(data);
|
||||
#endif
|
||||
} else if (dataType == DT_VOICE) {
|
||||
if (m_state != SS_RELAYING_NETWORK)
|
||||
return;
|
||||
|
||||
unsigned char fid = m_lc->getFID();
|
||||
if (fid == FID_ETSI || fid == FID_DMRA)
|
||||
; // AMBE FEC
|
||||
|
||||
// Change the color code in the EMB
|
||||
CEMB emb;
|
||||
emb.putData(data + 2U);
|
||||
emb.setColorCode(m_colorCode);
|
||||
emb.getData(data + 2U);
|
||||
|
||||
data[0U] = TAG_DATA;
|
||||
data[1U] = 0x00U;
|
||||
|
||||
writeNetworkQueue(data);
|
||||
|
||||
#if defined(DUMP_DMR)
|
||||
writeFile(data);
|
||||
#endif
|
||||
} else {
|
||||
if (m_state != SS_RELAYING_NETWORK)
|
||||
return;
|
||||
|
||||
// Change the Color Code of the Slot Type
|
||||
CSlotType slotType;
|
||||
slotType.putData(data + 2U);
|
||||
slotType.setColorCode(m_colorCode);
|
||||
slotType.getData(data + 2U);
|
||||
|
||||
// Convert the Data Sync to be from the BS
|
||||
CDMRSync sync;
|
||||
sync.addSync(data + 2U, DST_BS_DATA);
|
||||
|
||||
data[0U] = TAG_DATA;
|
||||
data[1U] = 0x00U;
|
||||
|
||||
writeNetworkQueue(data);
|
||||
|
||||
#if defined(DUMP_DMR)
|
||||
writeFile(data);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void CDMRSlot::clock(unsigned int ms)
|
||||
{
|
||||
m_timeoutTimer.clock(ms);
|
||||
|
||||
m_playoutTimer.clock(ms);
|
||||
if (m_playoutTimer.isRunning() && m_playoutTimer.hasExpired()) {
|
||||
while (!m_networkQueue.isEmpty()) {
|
||||
unsigned char len = 0U;
|
||||
m_networkQueue.getData(&len, 1U);
|
||||
|
||||
unsigned char buffer[100U];
|
||||
m_networkQueue.getData(buffer, len);
|
||||
|
||||
m_radioQueue.addData(&len, 1U);
|
||||
m_radioQueue.addData(buffer, len);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_state == SS_RELAYING_NETWORK) {
|
||||
m_networkWatchdog.clock(ms);
|
||||
|
||||
if (m_networkWatchdog.hasExpired()) {
|
||||
LogMessage("DMR Slot %u, network watchdog has expired", m_slotNo);
|
||||
writeEndOfTransmission();
|
||||
#if defined(DUMP_DMR)
|
||||
closeFile();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CDMRSlot::writeRadioQueue(const unsigned char *data)
|
||||
{
|
||||
unsigned char len = DMR_FRAME_LENGTH_BYTES + 2U;
|
||||
m_radioQueue.addData(&len, 1U);
|
||||
|
||||
// If the timeout has expired, replace the audio with idles to keep the slot busy
|
||||
if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired())
|
||||
m_radioQueue.addData(m_idle, len);
|
||||
else
|
||||
m_radioQueue.addData(data, len);
|
||||
}
|
||||
|
||||
void CDMRSlot::writeNetworkQueue(const unsigned char *data)
|
||||
{
|
||||
// If the timeout has expired, send nothing
|
||||
if (!m_timeoutTimer.isRunning() || !m_timeoutTimer.hasExpired()) {
|
||||
unsigned char len = DMR_FRAME_LENGTH_BYTES + 2U;
|
||||
m_networkQueue.addData(&len, 1U);
|
||||
|
||||
m_networkQueue.addData(data, len);
|
||||
}
|
||||
}
|
||||
|
||||
void CDMRSlot::writeNetwork(const unsigned char* data, unsigned char dataType)
|
||||
{
|
||||
assert(m_lc != NULL);
|
||||
|
||||
if (m_network == NULL)
|
||||
return;
|
||||
|
||||
// Don't send to the network if the timeout has expired
|
||||
if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired())
|
||||
return;
|
||||
|
||||
CDMRData dmrData;
|
||||
dmrData.setSlotNo(m_slotNo);
|
||||
dmrData.setDataType(dataType);
|
||||
dmrData.setSrcId(m_lc->getSrcId());
|
||||
dmrData.setDstId(m_lc->getDstId());
|
||||
dmrData.setFLCO(m_lc->getFLCO());
|
||||
dmrData.setN(m_n);
|
||||
dmrData.setSeqNo(m_seqNo);
|
||||
|
||||
m_seqNo++;
|
||||
|
||||
dmrData.setData(data + 2U);
|
||||
|
||||
m_network->write(dmrData);
|
||||
}
|
||||
|
||||
void CDMRSlot::init(unsigned int colorCode, CModem* modem, CHomebrewDMRIPSC* network, IDisplay* display)
|
||||
{
|
||||
assert(modem != NULL);
|
||||
assert(display != NULL);
|
||||
|
||||
m_colorCode = colorCode;
|
||||
m_modem = modem;
|
||||
m_network = network;
|
||||
m_display = display;
|
||||
|
||||
m_idle = new unsigned char[DMR_FRAME_LENGTH_BYTES + 2U];
|
||||
|
||||
::memcpy(m_idle + 2U, IDLE_DATA, DMR_FRAME_LENGTH_BYTES);
|
||||
|
||||
// Generate the Slot Type
|
||||
CSlotType slotType;
|
||||
slotType.setColorCode(colorCode);
|
||||
slotType.setDataType(DT_IDLE);
|
||||
slotType.getData(m_idle + 2U);
|
||||
|
||||
m_idle[0U] = TAG_DATA;
|
||||
m_idle[1U] = 0x00U;
|
||||
}
|
||||
|
||||
void CDMRSlot::setShortLC(unsigned int slotNo, unsigned int id, FLCO flco)
|
||||
{
|
||||
assert(m_modem != NULL);
|
||||
|
||||
switch (slotNo) {
|
||||
case 1U:
|
||||
m_id1 = 0U;
|
||||
m_flco1 = flco;
|
||||
if (id != 0U) {
|
||||
unsigned char buffer[3U];
|
||||
buffer[0U] = (id << 16) & 0xFFU;
|
||||
buffer[1U] = (id << 8) & 0xFFU;
|
||||
buffer[2U] = (id << 0) & 0xFFU;
|
||||
m_id1 = CCRC::crc8(buffer, 3U);
|
||||
}
|
||||
break;
|
||||
case 2U:
|
||||
m_id2 = 0U;
|
||||
m_flco2 = flco;
|
||||
if (id != 0U) {
|
||||
unsigned char buffer[3U];
|
||||
buffer[0U] = (id << 16) & 0xFFU;
|
||||
buffer[1U] = (id << 8) & 0xFFU;
|
||||
buffer[2U] = (id << 0) & 0xFFU;
|
||||
m_id2 = CCRC::crc8(buffer, 3U);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LogError("Invalid slot number passed to setShortLC - %u", slotNo);
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned char lc[5U];
|
||||
lc[0U] = 0x01U;
|
||||
lc[1U] = 0x00U;
|
||||
lc[2U] = 0x00U;
|
||||
lc[3U] = 0x00U;
|
||||
|
||||
if (m_id1 != 0U) {
|
||||
lc[2U] = m_id1;
|
||||
if (m_flco1 == FLCO_GROUP)
|
||||
lc[1U] |= 0x80U;
|
||||
else
|
||||
lc[1U] |= 0x90U;
|
||||
}
|
||||
|
||||
if (m_id2 != 0U) {
|
||||
lc[3U] = m_id2;
|
||||
if (m_flco2 == FLCO_GROUP)
|
||||
lc[1U] |= 0x08U;
|
||||
else
|
||||
lc[1U] |= 0x09U;
|
||||
}
|
||||
|
||||
lc[4U] = CCRC::crc8(lc, 4U);
|
||||
|
||||
unsigned char sLC[9U];
|
||||
|
||||
CUtils::dump(1U, "Input Short LC", lc, 5U);
|
||||
|
||||
CShortLC shortLC;
|
||||
shortLC.encode(lc, sLC);
|
||||
|
||||
CUtils::dump(1U, "Output Short LC", sLC, 9U);
|
||||
|
||||
m_modem->writeDMRShortLC(sLC);
|
||||
}
|
||||
|
||||
bool CDMRSlot::openFile()
|
||||
{
|
||||
if (m_fp != NULL)
|
||||
return true;
|
||||
|
||||
time_t t;
|
||||
::time(&t);
|
||||
|
||||
struct tm* tm = ::localtime(&t);
|
||||
|
||||
char name[100U];
|
||||
::sprintf(name, "DMR_%u_%04d%02d%02d_%02d%02d%02d.ambe", m_slotNo, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
|
||||
m_fp = ::fopen(name, "wb");
|
||||
if (m_fp == NULL)
|
||||
return false;
|
||||
|
||||
::fwrite("DMR", 1U, 3U, m_fp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDMRSlot::writeFile(const unsigned char* data)
|
||||
{
|
||||
if (m_fp == NULL)
|
||||
return false;
|
||||
|
||||
::fwrite(data, 1U, DMR_FRAME_LENGTH_BYTES + 2U, m_fp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CDMRSlot::closeFile()
|
||||
{
|
||||
if (m_fp != NULL) {
|
||||
::fclose(m_fp);
|
||||
m_fp = NULL;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* 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(DMRSlot_H)
|
||||
#define DMRSlot_H
|
||||
|
||||
#include "HomebrewDMRIPSC.h"
|
||||
#include "EmbeddedLC.h"
|
||||
#include "RingBuffer.h"
|
||||
#include "DMRSlot.h"
|
||||
#include "DMRData.h"
|
||||
#include "Display.h"
|
||||
#include "Timer.h"
|
||||
#include "Modem.h"
|
||||
#include "LC.h"
|
||||
|
||||
enum SLOT_STATE {
|
||||
SS_LISTENING,
|
||||
SS_LATE_ENTRY,
|
||||
SS_RELAYING_RF,
|
||||
SS_RELAYING_NETWORK
|
||||
};
|
||||
|
||||
class CDMRSlot {
|
||||
public:
|
||||
CDMRSlot(unsigned int slotNo, unsigned int timeout);
|
||||
~CDMRSlot();
|
||||
|
||||
void writeModem(unsigned char* data);
|
||||
|
||||
unsigned int readModem(unsigned char* data);
|
||||
|
||||
void writeNetwork(const CDMRData& data);
|
||||
|
||||
void clock(unsigned int ms);
|
||||
|
||||
static void init(unsigned int colorCode, CModem* modem, CHomebrewDMRIPSC* network, IDisplay* display);
|
||||
|
||||
private:
|
||||
unsigned int m_slotNo;
|
||||
CRingBuffer<unsigned char> m_radioQueue;
|
||||
CRingBuffer<unsigned char> m_networkQueue;
|
||||
SLOT_STATE m_state;
|
||||
CEmbeddedLC m_embeddedLC;
|
||||
CLC* m_lc;
|
||||
unsigned char m_seqNo;
|
||||
unsigned char m_n;
|
||||
CTimer m_playoutTimer;
|
||||
CTimer m_networkWatchdog;
|
||||
CTimer m_timeoutTimer;
|
||||
FILE* m_fp;
|
||||
|
||||
static unsigned int m_colorCode;
|
||||
static CModem* m_modem;
|
||||
static CHomebrewDMRIPSC* m_network;
|
||||
static IDisplay* m_display;
|
||||
|
||||
static unsigned char* m_idle;
|
||||
|
||||
static FLCO m_flco1;
|
||||
static unsigned char m_id1;
|
||||
static FLCO m_flco2;
|
||||
static unsigned char m_id2;
|
||||
|
||||
void writeRadioQueue(const unsigned char* data);
|
||||
void writeNetworkQueue(const unsigned char* data);
|
||||
void writeNetwork(const unsigned char* data, unsigned char dataType);
|
||||
|
||||
void writeEndOfTransmission();
|
||||
|
||||
bool openFile();
|
||||
bool writeFile(const unsigned char* data);
|
||||
void closeFile();
|
||||
|
||||
static void setShortLC(unsigned int slotNo, unsigned int id, FLCO flco = FLCO_GROUP);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* 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 "DMRSync.h"
|
||||
#include "DMRDefines.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
const unsigned int BITS_LOOKUP[] = {0U, 1U, 1U, 2U, 1U, 2U, 2U, 3U, 1U, 2U, 2U, 3U, 2U, 3U, 3U, 4U,
|
||||
1U, 2U, 2U, 3U, 2U, 3U, 3U, 4U, 2U, 3U, 3U, 4U, 3U, 4U, 4U, 5U,
|
||||
1U, 2U, 2U, 3U, 2U, 3U, 3U, 4U, 2U, 3U, 3U, 4U, 3U, 4U, 4U, 5U,
|
||||
2U, 3U, 3U, 4U, 3U, 4U, 4U, 5U, 3U, 4U, 4U, 5U, 4U, 5U, 5U, 6U,
|
||||
1U, 2U, 2U, 3U, 2U, 3U, 3U, 4U, 2U, 3U, 3U, 4U, 3U, 4U, 4U, 5U,
|
||||
2U, 3U, 3U, 4U, 3U, 4U, 4U, 5U, 3U, 4U, 4U, 5U, 4U, 5U, 5U, 6U,
|
||||
2U, 3U, 3U, 4U, 3U, 4U, 4U, 5U, 3U, 4U, 4U, 5U, 4U, 5U, 5U, 6U,
|
||||
3U, 4U, 4U, 5U, 4U, 5U, 5U, 6U, 4U, 5U, 5U, 6U, 5U, 6U, 6U, 7U,
|
||||
1U, 2U, 2U, 3U, 2U, 3U, 3U, 4U, 2U, 3U, 3U, 4U, 3U, 4U, 4U, 5U,
|
||||
2U, 3U, 3U, 4U, 3U, 4U, 4U, 5U, 3U, 4U, 4U, 5U, 4U, 5U, 5U, 6U,
|
||||
2U, 3U, 3U, 4U, 3U, 4U, 4U, 5U, 3U, 4U, 4U, 5U, 4U, 5U, 5U, 6U,
|
||||
3U, 4U, 4U, 5U, 4U, 5U, 5U, 6U, 4U, 5U, 5U, 6U, 5U, 6U, 6U, 7U,
|
||||
2U, 3U, 3U, 4U, 3U, 4U, 4U, 5U, 3U, 4U, 4U, 5U, 4U, 5U, 5U, 6U,
|
||||
3U, 4U, 4U, 5U, 4U, 5U, 5U, 6U, 4U, 5U, 5U, 6U, 5U, 6U, 6U, 7U,
|
||||
3U, 4U, 4U, 5U, 4U, 5U, 5U, 6U, 4U, 5U, 5U, 6U, 5U, 6U, 6U, 7U,
|
||||
4U, 5U, 5U, 6U, 5U, 6U, 6U, 7U, 5U, 6U, 6U, 7U, 6U, 7U, 7U, 8U};
|
||||
|
||||
const unsigned int THRESHOLD = 4U;
|
||||
|
||||
CDMRSync::CDMRSync()
|
||||
{
|
||||
}
|
||||
|
||||
CDMRSync::~CDMRSync()
|
||||
{
|
||||
}
|
||||
|
||||
DMR_SYNC_TYPE CDMRSync::matchDirectSync(const unsigned char* bytes) const
|
||||
{
|
||||
assert(bytes != NULL);
|
||||
|
||||
unsigned int diffs = compareBytes(bytes + 13U, DIRECT_SLOT1_AUDIO_SYNC);
|
||||
if (diffs < THRESHOLD)
|
||||
return DST_DIRECT_SLOT1_AUDIO;
|
||||
|
||||
diffs = compareBytes(bytes + 13U, DIRECT_SLOT2_AUDIO_SYNC);
|
||||
if (diffs < THRESHOLD)
|
||||
return DST_DIRECT_SLOT2_AUDIO;
|
||||
|
||||
diffs = compareBytes(bytes + 13U, DIRECT_SLOT1_DATA_SYNC);
|
||||
if (diffs < THRESHOLD)
|
||||
return DST_DIRECT_SLOT1_DATA;
|
||||
|
||||
diffs = compareBytes(bytes + 13U, DIRECT_SLOT2_DATA_SYNC);
|
||||
if (diffs < THRESHOLD)
|
||||
return DST_DIRECT_SLOT2_DATA;
|
||||
|
||||
return DST_NONE;
|
||||
}
|
||||
|
||||
DMR_SYNC_TYPE CDMRSync::matchMSSync(const unsigned char* bytes) const
|
||||
{
|
||||
assert(bytes != NULL);
|
||||
|
||||
unsigned int diffs = compareBytes(bytes + 13U, MS_SOURCED_AUDIO_SYNC);
|
||||
if (diffs < THRESHOLD)
|
||||
return DST_MS_AUDIO;
|
||||
|
||||
diffs = compareBytes(bytes + 13U, MS_SOURCED_DATA_SYNC);
|
||||
if (diffs < THRESHOLD)
|
||||
return DST_MS_DATA;
|
||||
|
||||
return DST_NONE;
|
||||
}
|
||||
|
||||
DMR_SYNC_TYPE CDMRSync::matchBSSync(const unsigned char* bytes) const
|
||||
{
|
||||
assert(bytes != NULL);
|
||||
|
||||
unsigned int diffs = compareBytes(bytes + 13U, BS_SOURCED_AUDIO_SYNC);
|
||||
if (diffs < THRESHOLD)
|
||||
return DST_BS_AUDIO;
|
||||
|
||||
diffs = compareBytes(bytes + 13U, BS_SOURCED_DATA_SYNC);
|
||||
if (diffs < THRESHOLD)
|
||||
return DST_BS_DATA;
|
||||
|
||||
return DST_NONE;
|
||||
}
|
||||
|
||||
void CDMRSync::addSync(unsigned char* data, DMR_SYNC_TYPE type) const
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
const unsigned char* sync = NULL;
|
||||
switch (type) {
|
||||
case DST_BS_AUDIO:
|
||||
sync = BS_SOURCED_AUDIO_SYNC;
|
||||
break;
|
||||
case DST_BS_DATA:
|
||||
sync = BS_SOURCED_DATA_SYNC;
|
||||
break;
|
||||
case DST_MS_AUDIO:
|
||||
sync = MS_SOURCED_AUDIO_SYNC;
|
||||
break;
|
||||
case DST_MS_DATA:
|
||||
sync = MS_SOURCED_DATA_SYNC;
|
||||
break;
|
||||
case DST_DIRECT_SLOT1_AUDIO:
|
||||
sync = DIRECT_SLOT1_AUDIO_SYNC;
|
||||
break;
|
||||
case DST_DIRECT_SLOT1_DATA:
|
||||
sync = DIRECT_SLOT1_DATA_SYNC;
|
||||
break;
|
||||
case DST_DIRECT_SLOT2_AUDIO:
|
||||
sync = DIRECT_SLOT2_AUDIO_SYNC;
|
||||
break;
|
||||
case DST_DIRECT_SLOT2_DATA:
|
||||
sync = DIRECT_SLOT2_DATA_SYNC;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0U; i < 7U; i++)
|
||||
data[i + 13U] = (data[i + 13U] & ~SYNC_MASK[i]) | sync[i];
|
||||
}
|
||||
|
||||
unsigned int CDMRSync::compareBytes(const unsigned char *bytes1, const unsigned char* bytes2) const
|
||||
{
|
||||
assert(bytes1 != NULL);
|
||||
assert(bytes2 != NULL);
|
||||
|
||||
unsigned int diffs = 0U;
|
||||
for (unsigned int i = 0U; i < 7U; i++) {
|
||||
unsigned char b = SYNC_MASK[i] & (bytes1[i] ^ bytes2[i]);
|
||||
diffs += BITS_LOOKUP[b];
|
||||
}
|
||||
|
||||
return diffs;
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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(DMRSYNC_H)
|
||||
#define DMRSYNC_H
|
||||
|
||||
enum DMR_SYNC_TYPE {
|
||||
DST_BS_AUDIO,
|
||||
DST_BS_DATA,
|
||||
|
||||
DST_MS_AUDIO,
|
||||
DST_MS_DATA,
|
||||
|
||||
DST_DIRECT_SLOT1_AUDIO,
|
||||
DST_DIRECT_SLOT1_DATA,
|
||||
|
||||
DST_DIRECT_SLOT2_AUDIO,
|
||||
DST_DIRECT_SLOT2_DATA,
|
||||
|
||||
DST_NONE
|
||||
};
|
||||
|
||||
class CDMRSync
|
||||
{
|
||||
public:
|
||||
CDMRSync();
|
||||
~CDMRSync();
|
||||
|
||||
DMR_SYNC_TYPE matchDirectSync(const unsigned char* bytes) const;
|
||||
|
||||
DMR_SYNC_TYPE matchMSSync(const unsigned char* bytes) const;
|
||||
|
||||
DMR_SYNC_TYPE matchBSSync(const unsigned char* bytes) const;
|
||||
|
||||
void addSync(unsigned char* data, DMR_SYNC_TYPE type) const;
|
||||
|
||||
private:
|
||||
unsigned int compareBytes(const unsigned char* bytes1, const unsigned char* bytes2) const;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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(DStarDefines_H)
|
||||
#define DStarDefines_H
|
||||
|
||||
const unsigned int DSTAR_HEADER_LENGTH_BYTES = 41U;
|
||||
const unsigned int DSTAR_FRAME_LENGTH_BYTES = 12U;
|
||||
|
||||
// Check this
|
||||
const unsigned char DSTAR_SYNC_BYTES[] = {0x55U, 0x2DU, 0x16U};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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 "DStarEcho.h"
|
||||
|
||||
CDStarEcho::CDStarEcho(unsigned int delay, unsigned int space) :
|
||||
m_buffer(space),
|
||||
m_timer(1000U, delay)
|
||||
{
|
||||
}
|
||||
|
||||
CDStarEcho::~CDStarEcho()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned int CDStarEcho::readData(unsigned char* data)
|
||||
{
|
||||
if (!hasData())
|
||||
return 0U;
|
||||
|
||||
unsigned char len;
|
||||
m_buffer.getData(&len, 1U);
|
||||
|
||||
m_buffer.getData(data, len);
|
||||
|
||||
if (!hasData())
|
||||
m_timer.stop();
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
bool CDStarEcho::writeData(const unsigned char* data, unsigned int length)
|
||||
{
|
||||
bool ret = m_buffer.hasSpace(length + 1U);
|
||||
if (!ret)
|
||||
return false;
|
||||
|
||||
unsigned char len = length;
|
||||
m_buffer.addData(&len, 1U);
|
||||
|
||||
m_buffer.addData(data, length);
|
||||
|
||||
m_timer.start();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDStarEcho::hasData()
|
||||
{
|
||||
if (m_timer.isRunning() && m_timer.hasExpired())
|
||||
return m_buffer.hasData();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void CDStarEcho::clock(unsigned int ms)
|
||||
{
|
||||
m_timer.clock(ms);
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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(DSTARECHO_H)
|
||||
#define DSTARECHO_H
|
||||
|
||||
#include "RingBuffer.h"
|
||||
#include "Timer.h"
|
||||
|
||||
class CDStarEcho {
|
||||
public:
|
||||
CDStarEcho(unsigned int delay, unsigned int space);
|
||||
~CDStarEcho();
|
||||
|
||||
unsigned int readData(unsigned char* data);
|
||||
|
||||
bool writeData(const unsigned char* data, unsigned int length);
|
||||
|
||||
bool hasData();
|
||||
|
||||
void clock(unsigned int ms);
|
||||
|
||||
private:
|
||||
CRingBuffer<unsigned char> m_buffer;
|
||||
CTimer m_timer;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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(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 TAG_HEADER = 0x00U;
|
||||
const unsigned char TAG_DATA = 0x01U;
|
||||
const unsigned char TAG_LOST = 0x02U;
|
||||
const unsigned char TAG_EOT = 0x03U;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (C) 2016 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "Display.h"
|
||||
|
||||
IDisplay::~IDisplay()
|
||||
{
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (C) 2016 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#if !defined(DISPLAY_H)
|
||||
#define DISPLAY_H
|
||||
|
||||
#include <string>
|
||||
|
||||
class IDisplay
|
||||
{
|
||||
public:
|
||||
virtual ~IDisplay() = 0;
|
||||
|
||||
virtual bool open() = 0;
|
||||
|
||||
virtual void setIdle() = 0;
|
||||
|
||||
virtual void setDStar() = 0;
|
||||
virtual void writeDStar(const std::string& call1, const std::string& call2) = 0;
|
||||
virtual void clearDStar() = 0;
|
||||
|
||||
virtual void setDMR() = 0;
|
||||
virtual void writeDMR(unsigned int slotNo, unsigned int srdId, bool group, unsigned int dstId) = 0;
|
||||
virtual void clearDMR(unsigned int slotNo) = 0;
|
||||
|
||||
virtual void setFusion() = 0;
|
||||
virtual void writeFusion(const std::string& callsign) = 0;
|
||||
virtual void clearFusion() = 0;
|
||||
|
||||
virtual void close() = 0;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* 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 "EMB.h"
|
||||
|
||||
#include "QR1676.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
CEMB::CEMB() :
|
||||
m_colorCode(0U),
|
||||
m_PI(false),
|
||||
m_LCSS(0U)
|
||||
{
|
||||
}
|
||||
|
||||
CEMB::~CEMB()
|
||||
{
|
||||
}
|
||||
|
||||
void CEMB::putData(const unsigned char* data)
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
unsigned char emb[2U];
|
||||
emb[0U] = (data[13U] << 4) & 0xF0U;
|
||||
emb[0U] |= (data[14U] >> 4) & 0x0FU;
|
||||
emb[1U] = (data[18U] << 4) & 0xF0U;
|
||||
emb[1U] |= (data[19U] >> 4) & 0x0FU;
|
||||
|
||||
CQR1676::decode(emb);
|
||||
|
||||
m_colorCode = (emb[0U] >> 4) & 0x0FU;
|
||||
m_PI = (emb[0U] & 0x08U) == 0x08U;
|
||||
m_LCSS = (emb[0U] >> 1) & 0x03U;
|
||||
}
|
||||
|
||||
void CEMB::getData(unsigned char* data) const
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
unsigned char emb[2U];
|
||||
emb[0U] = (m_colorCode << 4) & 0xF0U;
|
||||
emb[0U] |= m_PI ? 0x08U : 0x00U;
|
||||
emb[0U] |= (m_LCSS << 1) & 0x06U;
|
||||
emb[1U] = 0x00U;
|
||||
|
||||
CQR1676::encode(emb);
|
||||
|
||||
data[13U] = (data[13U] & 0xF0U) | ((emb[0U] >> 4U) & 0x0FU);
|
||||
data[14U] = (data[14U] & 0x0FU) | ((emb[0U] << 4U) & 0xF0U);
|
||||
data[18U] = (data[18U] & 0xF0U) | ((emb[1U] >> 4U) & 0x0FU);
|
||||
data[19U] = (data[19U] & 0x0FU) | ((emb[1U] << 4U) & 0xF0U);
|
||||
}
|
||||
|
||||
unsigned char CEMB::getColorCode() const
|
||||
{
|
||||
return m_colorCode;
|
||||
}
|
||||
|
||||
void CEMB::setColorCode(unsigned char code)
|
||||
{
|
||||
m_colorCode = code;
|
||||
}
|
||||
|
||||
bool CEMB::getPI() const
|
||||
{
|
||||
return m_PI;
|
||||
}
|
||||
|
||||
void CEMB::setPI(bool pi)
|
||||
{
|
||||
m_PI = pi;
|
||||
}
|
||||
|
||||
unsigned char CEMB::getLCSS() const
|
||||
{
|
||||
return m_LCSS;
|
||||
}
|
||||
|
||||
void CEMB::setLCSS(unsigned char lcss)
|
||||
{
|
||||
m_LCSS = lcss;
|
||||
}
|
|
@ -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(EMB_H)
|
||||
#define EMB_H
|
||||
|
||||
class CEMB
|
||||
{
|
||||
public:
|
||||
CEMB();
|
||||
~CEMB();
|
||||
|
||||
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,266 @@
|
|||
/*
|
||||
* 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 "EmbeddedLC.h"
|
||||
|
||||
#include "Hamming.h"
|
||||
#include "Utils.h"
|
||||
#include "CRC.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
CEmbeddedLC::CEmbeddedLC() :
|
||||
m_rawLC(NULL),
|
||||
m_state(LCS_NONE)
|
||||
{
|
||||
m_rawLC = new bool[128U];
|
||||
}
|
||||
|
||||
CEmbeddedLC::~CEmbeddedLC()
|
||||
{
|
||||
delete[] m_rawLC;
|
||||
}
|
||||
|
||||
// Add LC data (which may consist of 4 blocks) to the data store
|
||||
CLC* CEmbeddedLC::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_rawLC[a] = rawData[a + 4U];
|
||||
|
||||
// Show we are ready for the next LC block
|
||||
m_state = LCS_FIRST;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 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_rawLC[a + 32U] = rawData[a + 4U];
|
||||
|
||||
// Show we are ready for the next LC block
|
||||
m_state = LCS_SECOND;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 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_rawLC[a + 64U] = rawData[a + 4U];
|
||||
|
||||
// Show we are ready for the final LC block
|
||||
m_state = LCS_THIRD;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 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_rawLC[a + 96U] = rawData[a + 4U];
|
||||
|
||||
// Process the complete data block
|
||||
return processMultiBlockEmbeddedLC();
|
||||
}
|
||||
|
||||
// Is this a single block embedded LC
|
||||
if (lcss == 0U) {
|
||||
processSingleBlockEmbeddedLC(rawData + 4U);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CEmbeddedLC::setData(const CLC& lc)
|
||||
{
|
||||
bool lcData[72U];
|
||||
lc.getData(lcData);
|
||||
|
||||
unsigned int crc;
|
||||
CCRC::encodeFiveBit(lcData, 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] = lcData[b];
|
||||
for (unsigned int a = 16U; a < 27U; a++, b++)
|
||||
data[a] = lcData[b];
|
||||
for (unsigned int a = 32U; a < 42U; a++, b++)
|
||||
data[a] = lcData[b];
|
||||
for (unsigned int a = 48U; a < 58U; a++, b++)
|
||||
data[a] = lcData[b];
|
||||
for (unsigned int a = 64U; a < 74U; a++, b++)
|
||||
data[a] = lcData[b];
|
||||
for (unsigned int a = 80U; a < 90U; a++, b++)
|
||||
data[a] = lcData[b];
|
||||
for (unsigned int a = 96U; a < 106U; a++, b++)
|
||||
data[a] = lcData[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_rawLC[a] = data[b];
|
||||
b += 16U;
|
||||
if (b > 127U)
|
||||
b -= 127U;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int CEmbeddedLC::getData(unsigned char* data, unsigned int n) const
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
if (n < 4U) {
|
||||
bool bits[40U];
|
||||
::memset(bits, 0x00U, 40U * sizeof(bool));
|
||||
::memcpy(bits + 4U, m_rawLC + 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);
|
||||
} else {
|
||||
data[14U] &= 0xF0U;
|
||||
data[15U] = 0x00U;
|
||||
data[16U] = 0x00U;
|
||||
data[17U] = 0x00U;
|
||||
data[18U] &= 0x0FU;
|
||||
}
|
||||
|
||||
switch (n) {
|
||||
case 0U:
|
||||
return 1U;
|
||||
case 1U:
|
||||
case 2U:
|
||||
return 3U;
|
||||
case 3U:
|
||||
return 2U;
|
||||
default:
|
||||
return 0U;
|
||||
}
|
||||
}
|
||||
|
||||
// Unpack and error check an embedded LC
|
||||
CLC* CEmbeddedLC::processMultiBlockEmbeddedLC()
|
||||
{
|
||||
// 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_rawLC[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)) {
|
||||
::LogDebug("Hamming decode of a row of the Embedded LC failed");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
::LogDebug("Parity check of a column of the Embedded LC failed");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// We have passed the Hamming check so extract the actual payload
|
||||
bool lcData[72U];
|
||||
b = 0U;
|
||||
for (unsigned int a = 0U; a < 11U; a++, b++)
|
||||
lcData[b] = data[a];
|
||||
for (unsigned int a = 16U; a < 27U; a++, b++)
|
||||
lcData[b] = data[a];
|
||||
for (unsigned int a = 32U; a < 42U; a++, b++)
|
||||
lcData[b] = data[a];
|
||||
for (unsigned int a = 48U; a < 58U; a++, b++)
|
||||
lcData[b] = data[a];
|
||||
for (unsigned int a = 64U; a < 74U; a++, b++)
|
||||
lcData[b] = data[a];
|
||||
for (unsigned int a = 80U; a < 90U; a++, b++)
|
||||
lcData[b] = data[a];
|
||||
for (unsigned int a = 96U; a < 106U; a++, b++)
|
||||
lcData[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(lcData, crc)) {
|
||||
::LogDebug("Checksum of the Embedded LC failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new CLC(lcData);
|
||||
}
|
||||
|
||||
// Deal with a single block embedded LC
|
||||
void CEmbeddedLC::processSingleBlockEmbeddedLC(const bool* data)
|
||||
{
|
||||
// Nothing interesting, or just NULL (I think)
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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 EmbeddedLC_H
|
||||
#define EmbeddedLC_H
|
||||
|
||||
#include "LC.h"
|
||||
|
||||
enum LC_STATE {
|
||||
LCS_NONE,
|
||||
LCS_FIRST,
|
||||
LCS_SECOND,
|
||||
LCS_THIRD
|
||||
};
|
||||
|
||||
class CEmbeddedLC
|
||||
{
|
||||
public:
|
||||
CEmbeddedLC();
|
||||
~CEmbeddedLC();
|
||||
|
||||
CLC* addData(const unsigned char* data, unsigned char lcss);
|
||||
|
||||
void setData(const CLC& lc);
|
||||
unsigned int getData(unsigned char* data, unsigned int n) const;
|
||||
|
||||
private:
|
||||
bool* m_rawLC;
|
||||
LC_STATE m_state;
|
||||
|
||||
CLC* processMultiBlockEmbeddedLC();
|
||||
void processSingleBlockEmbeddedLC(const bool* data);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* 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 "FullLC.h"
|
||||
#include "Log.h"
|
||||
#include "DMRDefines.h"
|
||||
#include "RS129.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
CFullLC::CFullLC() :
|
||||
m_bptc()
|
||||
{
|
||||
}
|
||||
|
||||
CFullLC::~CFullLC()
|
||||
{
|
||||
}
|
||||
|
||||
CLC* CFullLC::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)) {
|
||||
::LogDebug("Checksum failed for the LC");
|
||||
CLC lc(lcData);
|
||||
LogDebug("Invalid LC, src = %u, dst = %s%u", lc.getSrcId(), lc.getFLCO() == FLCO_GROUP ? "TG " : "", lc.getDstId());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new CLC(lcData);
|
||||
}
|
||||
|
||||
void CFullLC::encode(const CLC& 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 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 FullLC_H
|
||||
#define FullLC_H
|
||||
|
||||
#include "LC.h"
|
||||
#include "SlotType.h"
|
||||
|
||||
#include "BPTC19696.h"
|
||||
|
||||
class CFullLC
|
||||
{
|
||||
public:
|
||||
CFullLC();
|
||||
~CFullLC();
|
||||
|
||||
CLC* decode(const unsigned char* data, unsigned char type);
|
||||
|
||||
void encode(const CLC& lc, unsigned char* data, unsigned char type);
|
||||
|
||||
private:
|
||||
CBPTC19696 m_bptc;
|
||||
};
|
||||
|
||||
#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
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* 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 "Hamming.h"
|
||||
|
||||
// Hamming (15,11,3) check a boolean data array
|
||||
bool CHamming::decode15113(bool* d)
|
||||
{
|
||||
// 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(bool* d)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
// 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];
|
||||
}
|
||||
|
||||
// A Hamming (16,11,4) Check
|
||||
bool CHamming::decode16114(bool* d)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
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,37 @@
|
|||
/*
|
||||
* 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 Hamming_H
|
||||
#define Hamming_H
|
||||
|
||||
class CHamming {
|
||||
public:
|
||||
static void encode15113(bool* d);
|
||||
static bool decode15113(bool* d);
|
||||
|
||||
static void encode1393(bool* d);
|
||||
static bool decode1393(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,418 @@
|
|||
/*
|
||||
* 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 "HomebrewDMRIPSC.h"
|
||||
#include "StopWatch.h"
|
||||
#include "SHA256.h"
|
||||
#include "Utils.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
const unsigned int BUFFER_LENGTH = 500U;
|
||||
|
||||
const unsigned int HOMEBREW_DATA_PACKET_LENGTH = 53U;
|
||||
|
||||
|
||||
CHomebrewDMRIPSC::CHomebrewDMRIPSC(const std::string& address, unsigned int port, unsigned int id, const std::string& password, const char* software, const char* version, bool debug) :
|
||||
m_address(),
|
||||
m_port(port),
|
||||
m_id(NULL),
|
||||
m_password(password),
|
||||
m_debug(debug),
|
||||
m_software(software),
|
||||
m_version(version),
|
||||
m_socket(),
|
||||
m_status(DISCONNECTED),
|
||||
m_retryTimer(1000U, 10U),
|
||||
m_timeoutTimer(1000U, 600U),
|
||||
m_pingTimer(1000U, 5U),
|
||||
m_buffer(NULL),
|
||||
m_salt(NULL),
|
||||
m_streamId(NULL),
|
||||
m_rxData(1000U),
|
||||
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());
|
||||
|
||||
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_streamId[0U] = 0x00U;
|
||||
m_streamId[1U] = 0x00U;
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
CHomebrewDMRIPSC::~CHomebrewDMRIPSC()
|
||||
{
|
||||
delete[] m_buffer;
|
||||
delete[] m_salt;
|
||||
delete[] m_streamId;
|
||||
delete[] m_id;
|
||||
}
|
||||
|
||||
void CHomebrewDMRIPSC::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 CHomebrewDMRIPSC::open()
|
||||
{
|
||||
LogMessage("Opening DMR IPSC");
|
||||
|
||||
bool ret = m_socket.open();
|
||||
if (!ret)
|
||||
return false;
|
||||
|
||||
ret = writeLogin();
|
||||
if (!ret) {
|
||||
m_socket.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_status = WAITING_LOGIN;
|
||||
m_timeoutTimer.start();
|
||||
m_retryTimer.start();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CHomebrewDMRIPSC::read(CDMRData& data)
|
||||
{
|
||||
if (m_status != RUNNING)
|
||||
return false;
|
||||
|
||||
if (m_rxData.isEmpty())
|
||||
return false;
|
||||
|
||||
unsigned char length = 0U;
|
||||
|
||||
m_rxData.getData(&length, 1U);
|
||||
m_rxData.getData(m_buffer, length);
|
||||
|
||||
// Is this a data packet?
|
||||
if (::memcmp(m_buffer, "DMRD", 4U) != 0)
|
||||
return false;
|
||||
|
||||
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);
|
||||
|
||||
unsigned int slotNo = (m_buffer[15U] & 0x80U) == 0x80U ? 2U : 1U;
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool CHomebrewDMRIPSC::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();
|
||||
buffer[15U] = slotNo == 1U ? 0x00U : 0x80U;
|
||||
|
||||
FLCO flco = data.getFLCO();
|
||||
buffer[15U] |= flco == FLCO_GROUP ? 0x00U : 0x40U;
|
||||
|
||||
unsigned int slotIndex = slotNo - 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 || dataType == DT_DATA_HEADER) && data.getSeqNo() == 0U)
|
||||
m_streamId[slotIndex] = ::rand() + 1U;
|
||||
|
||||
buffer[15U] |= (0x20U | dataType);
|
||||
}
|
||||
|
||||
buffer[4U] = data.getSeqNo();
|
||||
|
||||
::memcpy(buffer + 16U, m_streamId + slotIndex, 4U);
|
||||
|
||||
data.getData(buffer + 20U);
|
||||
|
||||
return write(buffer, HOMEBREW_DATA_PACKET_LENGTH);
|
||||
}
|
||||
|
||||
void CHomebrewDMRIPSC::close()
|
||||
{
|
||||
LogMessage("Closing DMR IPSC");
|
||||
|
||||
unsigned char buffer[9U];
|
||||
::memcpy(buffer + 0U, "RPTCL", 5U);
|
||||
::memcpy(buffer + 5U, m_id, 4U);
|
||||
write(buffer, 9U);
|
||||
|
||||
m_socket.close();
|
||||
}
|
||||
|
||||
void CHomebrewDMRIPSC::clock(unsigned int ms)
|
||||
{
|
||||
in_addr address;
|
||||
unsigned int port;
|
||||
int length = m_socket.read(m_buffer, BUFFER_LENGTH, address, port);
|
||||
|
||||
if (m_debug && length > 0)
|
||||
CUtils::dump(1U, "IPSC Received", m_buffer, length);
|
||||
|
||||
if (length > 0 && m_address.s_addr == address.s_addr && m_port == port) {
|
||||
if (::memcmp(m_buffer, "DMRD", 4U) == 0) {
|
||||
unsigned char len = length;
|
||||
m_rxData.addData(&len, 1U);
|
||||
m_rxData.addData(m_buffer, len);
|
||||
} else if (::memcmp(m_buffer, "MSTNAK", 6U) == 0) {
|
||||
LogError("Login to the master has failed");
|
||||
m_status = DISCONNECTED; // XXX
|
||||
m_timeoutTimer.stop();
|
||||
m_retryTimer.stop();
|
||||
} else if (::memcmp(m_buffer, "RPTACK", 6U) == 0) {
|
||||
switch (m_status) {
|
||||
case WAITING_LOGIN:
|
||||
::memcpy(m_salt, m_buffer + 6U, sizeof(uint32_t));
|
||||
writeAuthorisation();
|
||||
m_status = WAITING_AUTHORISATION;
|
||||
m_timeoutTimer.start();
|
||||
m_retryTimer.start();
|
||||
break;
|
||||
case WAITING_AUTHORISATION:
|
||||
writeConfig();
|
||||
m_status = WAITING_CONFIG;
|
||||
m_timeoutTimer.start();
|
||||
m_retryTimer.start();
|
||||
break;
|
||||
case WAITING_CONFIG:
|
||||
LogMessage("Logged into the master succesfully");
|
||||
m_status = RUNNING;
|
||||
m_timeoutTimer.start();
|
||||
m_retryTimer.stop();
|
||||
m_pingTimer.start();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (::memcmp(m_buffer, "MSTCL", 5U) == 0) {
|
||||
LogError("Master is closing down");
|
||||
m_status = DISCONNECTED; // XXX
|
||||
m_timeoutTimer.stop();
|
||||
m_retryTimer.stop();
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_status != RUNNING) {
|
||||
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_CONFIG:
|
||||
writeConfig();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
m_retryTimer.start();
|
||||
}
|
||||
} else {
|
||||
m_pingTimer.clock(ms);
|
||||
if (m_pingTimer.isRunning() && m_pingTimer.hasExpired()) {
|
||||
writePing();
|
||||
m_pingTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
m_timeoutTimer.clock(ms);
|
||||
if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) {
|
||||
LogError("Connection to the master has timed out");
|
||||
m_status = DISCONNECTED;
|
||||
m_timeoutTimer.stop();
|
||||
m_retryTimer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
bool CHomebrewDMRIPSC::writeLogin()
|
||||
{
|
||||
unsigned char buffer[8U];
|
||||
|
||||
::memcpy(buffer + 0U, "RPTL", 4U);
|
||||
::memcpy(buffer + 4U, m_id, 4U);
|
||||
|
||||
return write(buffer, 8U);
|
||||
}
|
||||
|
||||
bool CHomebrewDMRIPSC::writeAuthorisation()
|
||||
{
|
||||
unsigned int size = m_password.size();
|
||||
|
||||
unsigned char* in = new unsigned char[size + sizeof(uint32_t)];
|
||||
::memcpy(in, m_salt, sizeof(uint32_t));
|
||||
for (unsigned int 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, size + sizeof(uint32_t), out + 8U);
|
||||
|
||||
delete[] in;
|
||||
|
||||
return write(out, 40U);
|
||||
}
|
||||
|
||||
bool CHomebrewDMRIPSC::writeConfig()
|
||||
{
|
||||
char buffer[400U];
|
||||
|
||||
::memcpy(buffer + 0U, "RPTC", 4U);
|
||||
::memcpy(buffer + 4U, m_id, 4U);
|
||||
|
||||
::sprintf(buffer + 8U, "%-8.8s%09u%09u%02u%02u%-08f%-09f%03d%-20.20s%-20.20s%-124.124s%-40.40s%-40.40s", m_callsign.c_str(),
|
||||
m_rxFrequency, m_txFrequency, m_power, m_colorCode, m_latitude, m_longitude, m_height, m_location.c_str(),
|
||||
m_description.c_str(), m_url.c_str(), m_software, m_version);
|
||||
|
||||
return write((unsigned char*)buffer, 302U);
|
||||
}
|
||||
|
||||
bool CHomebrewDMRIPSC::writePing()
|
||||
{
|
||||
unsigned char buffer[11U];
|
||||
|
||||
::memcpy(buffer + 0U, "RPTPING", 7U);
|
||||
::memcpy(buffer + 7U, m_id, 4U);
|
||||
|
||||
return write(buffer, 11U);
|
||||
}
|
||||
|
||||
bool CHomebrewDMRIPSC::wantsBeacon()
|
||||
{
|
||||
bool beacon = m_beacon;
|
||||
|
||||
m_beacon = false;
|
||||
|
||||
return beacon;
|
||||
}
|
||||
|
||||
bool CHomebrewDMRIPSC::write(const unsigned char* data, unsigned int length)
|
||||
{
|
||||
assert(data != NULL);
|
||||
assert(length > 0U);
|
||||
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "IPSC Transmitted", data, length);
|
||||
|
||||
return m_socket.write(data, length, m_address, m_port);
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* 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(HOMEBREWDMRIPSC_H)
|
||||
#define HOMEBREWDMRIPSC_H
|
||||
|
||||
#include "UDPSocket.h"
|
||||
#include "Timer.h"
|
||||
#include "RingBuffer.h"
|
||||
#include "DMRData.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
typedef unsigned int uint32_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned char uint8_t;
|
||||
#else
|
||||
#include <cstdint>
|
||||
#endif
|
||||
|
||||
class CHomebrewDMRIPSC
|
||||
{
|
||||
public:
|
||||
CHomebrewDMRIPSC(const std::string& address, unsigned int port, unsigned int id, const std::string& password, const char* software, const char* version, bool debug);
|
||||
~CHomebrewDMRIPSC();
|
||||
|
||||
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();
|
||||
|
||||
bool read(CDMRData& data);
|
||||
|
||||
bool write(const CDMRData& data);
|
||||
|
||||
bool wantsBeacon();
|
||||
|
||||
void clock(unsigned int ms);
|
||||
|
||||
void close();
|
||||
|
||||
private:
|
||||
in_addr m_address;
|
||||
unsigned int m_port;
|
||||
uint8_t* m_id;
|
||||
std::string m_password;
|
||||
bool m_debug;
|
||||
const char* m_software;
|
||||
const char* m_version;
|
||||
CUDPSocket m_socket;
|
||||
|
||||
enum STATUS {
|
||||
DISCONNECTED,
|
||||
WAITING_LOGIN,
|
||||
WAITING_AUTHORISATION,
|
||||
WAITING_CONFIG,
|
||||
RUNNING
|
||||
};
|
||||
|
||||
STATUS m_status;
|
||||
CTimer m_retryTimer;
|
||||
CTimer m_timeoutTimer;
|
||||
CTimer m_pingTimer;
|
||||
unsigned char* m_buffer;
|
||||
unsigned char* m_salt;
|
||||
uint32_t* m_streamId;
|
||||
|
||||
CRingBuffer<unsigned char> m_rxData;
|
||||
|
||||
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 writeConfig();
|
||||
bool writePing();
|
||||
|
||||
bool write(const unsigned char* data, unsigned int length);
|
||||
};
|
||||
|
||||
#endif
|
After Width: | Height: | Size: 450 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 944 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 874 KiB |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 102 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 112 KiB |
After Width: | Height: | Size: 49 KiB |
After Width: | Height: | Size: 148 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 59 KiB |
After Width: | Height: | Size: 5.7 KiB |
After Width: | Height: | Size: 148 KiB |
After Width: | Height: | Size: 39 KiB |
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* 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 "LC.h"
|
||||
|
||||
#include "Utils.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
CLC::CLC(FLCO flco, unsigned int srcId, unsigned int dstId) :
|
||||
m_PF(false),
|
||||
m_FLCO(flco),
|
||||
m_FID(0U),
|
||||
m_srcId(srcId),
|
||||
m_dstId(dstId)
|
||||
{
|
||||
}
|
||||
|
||||
CLC::CLC(const unsigned char* bytes) :
|
||||
m_PF(false),
|
||||
m_FLCO(FLCO_GROUP),
|
||||
m_FID(0U),
|
||||
m_srcId(0U),
|
||||
m_dstId(0U)
|
||||
{
|
||||
assert(bytes != NULL);
|
||||
|
||||
m_PF = (bytes[0U] & 0x80U) == 0x80U;
|
||||
|
||||
m_FLCO = FLCO(bytes[0U] & 0x3FU);
|
||||
|
||||
m_FID = bytes[1U];
|
||||
|
||||
m_dstId = bytes[3U] << 16 | bytes[4U] << 8 | bytes[5U];
|
||||
m_srcId = bytes[6U] << 16 | bytes[7U] << 8 | bytes[8U];
|
||||
}
|
||||
|
||||
CLC::CLC(const bool* bits) :
|
||||
m_PF(false),
|
||||
m_FLCO(FLCO_GROUP),
|
||||
m_FID(0U),
|
||||
m_srcId(0U),
|
||||
m_dstId(0U)
|
||||
{
|
||||
assert(bits != NULL);
|
||||
|
||||
m_PF = bits[0U];
|
||||
|
||||
unsigned char temp1, temp2;
|
||||
CUtils::bitsToByteBE(bits + 0U, temp1);
|
||||
m_FLCO = FLCO(temp1 & 0x3FU);
|
||||
|
||||
CUtils::bitsToByteBE(bits + 8U, temp2);
|
||||
m_FID = temp2;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
CLC::CLC() :
|
||||
m_PF(false),
|
||||
m_FLCO(FLCO_GROUP),
|
||||
m_FID(0U),
|
||||
m_srcId(0U),
|
||||
m_dstId(0U)
|
||||
{
|
||||
}
|
||||
|
||||
CLC::~CLC()
|
||||
{
|
||||
}
|
||||
|
||||
void CLC::getData(unsigned char* bytes) const
|
||||
{
|
||||
assert(bytes != NULL);
|
||||
|
||||
bytes[0U] = (unsigned char)m_FLCO;
|
||||
|
||||
if (m_PF)
|
||||
bytes[0U] |= 0x80U;
|
||||
|
||||
bytes[1U] = m_FID;
|
||||
|
||||
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 CLC::getData(bool* bits) const
|
||||
{
|
||||
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 CLC::getPF() const
|
||||
{
|
||||
return m_PF;
|
||||
}
|
||||
|
||||
void CLC::setPF(bool pf)
|
||||
{
|
||||
m_PF = pf;
|
||||
}
|
||||
|
||||
FLCO CLC::getFLCO() const
|
||||
{
|
||||
return m_FLCO;
|
||||
}
|
||||
|
||||
void CLC::setFLCO(FLCO flco)
|
||||
{
|
||||
m_FLCO = flco;
|
||||
}
|
||||
|
||||
unsigned char CLC::getFID() const
|
||||
{
|
||||
return m_FID;
|
||||
}
|
||||
|
||||
void CLC::setFID(unsigned char fid)
|
||||
{
|
||||
m_FID = fid;
|
||||
}
|
||||
|
||||
unsigned int CLC::getSrcId() const
|
||||
{
|
||||
return m_srcId;
|
||||
}
|
||||
|
||||
void CLC::setSrcId(unsigned int id)
|
||||
{
|
||||
m_srcId = id;
|
||||
}
|
||||
|
||||
unsigned int CLC::getDstId() const
|
||||
{
|
||||
return m_dstId;
|
||||
}
|
||||
|
||||
void CLC::setDstId(unsigned int id)
|
||||
{
|
||||
m_dstId = id;
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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(LC_H)
|
||||
#define LC_H
|
||||
|
||||
#include "DMRDefines.h"
|
||||
|
||||
class CLC
|
||||
{
|
||||
public:
|
||||
CLC(FLCO flco, unsigned int srcId, unsigned int dstId);
|
||||
CLC(const unsigned char* bytes);
|
||||
CLC(const bool* bits);
|
||||
CLC();
|
||||
~CLC();
|
||||
|
||||
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;
|
||||
FLCO m_FLCO;
|
||||
unsigned char m_FID;
|
||||
unsigned int m_srcId;
|
||||
unsigned int m_dstId;
|
||||
};
|
||||
|
||||
#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,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 "Log.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstdarg>
|
||||
#include <ctime>
|
||||
#include <cassert>
|
||||
|
||||
static std::string m_path;
|
||||
static std::string m_root;
|
||||
|
||||
static FILE* m_fpLog = NULL;
|
||||
|
||||
static bool m_display = true;
|
||||
|
||||
static unsigned int m_level = 2U;
|
||||
|
||||
static struct tm m_tm;
|
||||
|
||||
static char LEVELS[] = " DMIWEF";
|
||||
|
||||
static bool LogOpen()
|
||||
{
|
||||
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[50U];
|
||||
#if defined(WIN32)
|
||||
::sprintf(filename, "%s\\%s-%04d-%02d-%02d.log", m_path.c_str(), m_root.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
|
||||
#else
|
||||
::sprintf(filename, "%s/%s-%04d-%02d-%02d.log", m_path.c_str(), m_root.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& path, const std::string& root, bool display)
|
||||
{
|
||||
m_path = path;
|
||||
m_root = root;
|
||||
m_display = display;
|
||||
return ::LogOpen();
|
||||
}
|
||||
|
||||
void LogFinalise()
|
||||
{
|
||||
if (m_fpLog != NULL)
|
||||
::fclose(m_fpLog);
|
||||
}
|
||||
|
||||
void LogSetLevel(unsigned int level)
|
||||
{
|
||||
m_level = level;
|
||||
}
|
||||
|
||||
void Log(unsigned int level, const char* fmt, ...)
|
||||
{
|
||||
assert(level < 7U);
|
||||
assert(fmt != NULL);
|
||||
|
||||
if (level < m_level)
|
||||
return;
|
||||
|
||||
bool ret = ::LogOpen();
|
||||
if (!ret)
|
||||
return;
|
||||
|
||||
time_t now;
|
||||
::time(&now);
|
||||
|
||||
struct tm* tm = ::gmtime(&now);
|
||||
|
||||
::fprintf(m_fpLog, "%c: %04d-%02d-%02d %02d:%02d:%02d ", LEVELS[level], tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
if (m_display)
|
||||
::fprintf(stdout, "%c: %04d-%02d-%02d %02d:%02d:%02d ", LEVELS[level], tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
|
||||
va_list vl;
|
||||
va_start(vl, fmt);
|
||||
vfprintf(m_fpLog, fmt, vl);
|
||||
if (m_display)
|
||||
vfprintf(stdout, fmt, vl);
|
||||
va_end(vl);
|
||||
|
||||
::fprintf(m_fpLog, "\n");
|
||||
::fflush(m_fpLog);
|
||||
|
||||
if (m_display) {
|
||||
::fprintf(stdout, "\n");
|
||||
::fflush(stdout);
|
||||
}
|
||||
|
||||
if (level == 6U) { // Fatal
|
||||
::fclose(m_fpLog);
|
||||
exit(1);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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(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& path, const std::string& root, bool display);
|
||||
extern void LogFinalise();
|
||||
|
||||
extern void LogSetLevel(unsigned int level);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,70 @@
|
|||
[General]
|
||||
Callsign=G9BF
|
||||
Timeout=120
|
||||
Duplex=1
|
||||
ModeHang=10
|
||||
Display=None
|
||||
|
||||
[Info]
|
||||
RXFrequency=435000000
|
||||
TXFrequency=435000000
|
||||
Power=1
|
||||
Latitude=51.0
|
||||
Longitude=-1.0
|
||||
Height=0
|
||||
Location=Nowhere
|
||||
Description=Multi-Mode Repeater
|
||||
URL=www.google.co.uk
|
||||
|
||||
[Log]
|
||||
# Logging levels, 0=No logging
|
||||
Level=1
|
||||
Path=.
|
||||
Root=MMDVM
|
||||
Display=1
|
||||
|
||||
[Modem]
|
||||
# Port=/dev/ttyACM0
|
||||
Port=\\.\COM3
|
||||
TXInvert=1
|
||||
RXInvert=0
|
||||
PTTInvert=0
|
||||
TXDelay=100
|
||||
RXLevel=50
|
||||
TXLevel=50
|
||||
Debug=0
|
||||
|
||||
[D-Star]
|
||||
Enable=1
|
||||
Module=C
|
||||
|
||||
[DMR]
|
||||
Enable=1
|
||||
Id=123456
|
||||
ColorCode=1
|
||||
|
||||
[System Fusion]
|
||||
Enable=1
|
||||
|
||||
[D-Star Network]
|
||||
Enable=1
|
||||
GatewayAddress=127.0.0.1
|
||||
GatewayPort=20010
|
||||
LocalPort=20011
|
||||
Debug=0
|
||||
|
||||
[DMR Network]
|
||||
Enable=1
|
||||
Address=44.131.4.1
|
||||
Port=62031
|
||||
Password=PASSWORD
|
||||
Debug=1
|
||||
|
||||
[System Fusion Network]
|
||||
Enable=0
|
||||
Address=44.131.4.1
|
||||
Port=32768
|
||||
Debug=1
|
||||
|
||||
[TFT Serial]
|
||||
Port=/dev/ttyAMA0
|
|
@ -0,0 +1,473 @@
|
|||
/*
|
||||
* 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 "MMDVMHost.h"
|
||||
#include "Log.h"
|
||||
#include "Version.h"
|
||||
#include "StopWatch.h"
|
||||
#include "Defines.h"
|
||||
#include "DMRControl.h"
|
||||
#include "TFTSerial.h"
|
||||
#include "NullDisplay.h"
|
||||
|
||||
#include "DStarEcho.h"
|
||||
#include "YSFEcho.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#if !defined(WIN32)
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
static bool m_killed = false;
|
||||
|
||||
#if !defined(WIN32)
|
||||
static void sigHandler(int)
|
||||
{
|
||||
m_killed = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
const char* HEADER1 = "This software is for use on amateur radio networks only.";
|
||||
const char* HEADER2 = "Its use on commercial networks is strictly prohibited.";
|
||||
const char* HEADER3 = "Copyright(C) 2015, 2016 by Jonathan Naylor, G4KLX";
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc == 1) {
|
||||
::fprintf(stderr, "Usage: MMDVMHost <conf file>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if !defined(WIN32)
|
||||
::signal(SIGUSR1, sigHandler);
|
||||
#endif
|
||||
|
||||
CMMDVMHost* host = new CMMDVMHost(std::string(argv[1]));
|
||||
int ret2 = host->run();
|
||||
|
||||
delete host;
|
||||
|
||||
::LogFinalise();
|
||||
|
||||
return ret2;
|
||||
}
|
||||
|
||||
CMMDVMHost::CMMDVMHost(const std::string& confFile) :
|
||||
m_conf(confFile),
|
||||
m_modem(NULL),
|
||||
m_dmrNetwork(NULL),
|
||||
m_display(NULL),
|
||||
m_dstarEnabled(false),
|
||||
m_dmrEnabled(false),
|
||||
m_ysfEnabled(false)
|
||||
{
|
||||
}
|
||||
|
||||
CMMDVMHost::~CMMDVMHost()
|
||||
{
|
||||
}
|
||||
|
||||
int CMMDVMHost::run()
|
||||
{
|
||||
bool ret = m_conf.read();
|
||||
if (!ret) {
|
||||
::fprintf(stderr, "MMDVMHost: cannot read the .ini file\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = ::LogInitialise(m_conf.getLogPath(), m_conf.getLogRoot(), m_conf.getLogDisplay());
|
||||
if (!ret) {
|
||||
::fprintf(stderr, "MMDVMHost: unable to open the log file\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
::LogSetLevel(m_conf.getLogLevel());
|
||||
|
||||
LogInfo(HEADER1);
|
||||
LogInfo(HEADER2);
|
||||
LogInfo(HEADER3);
|
||||
|
||||
LogMessage("MMDVMHost-%s is starting", VERSION);
|
||||
|
||||
readParams();
|
||||
|
||||
ret = createModem();
|
||||
if (!ret)
|
||||
return 1;
|
||||
|
||||
createDisplay();
|
||||
|
||||
if (m_dmrEnabled) {
|
||||
ret = createDMRNetwork();
|
||||
if (!ret)
|
||||
return 1;
|
||||
}
|
||||
|
||||
CStopWatch stopWatch;
|
||||
stopWatch.start();
|
||||
|
||||
CDStarEcho* dstar = NULL;
|
||||
if (m_dstarEnabled)
|
||||
dstar = new CDStarEcho(2U, 10000U);
|
||||
|
||||
CDMRControl* dmr = NULL;
|
||||
if (m_dmrEnabled) {
|
||||
unsigned int id = m_conf.getDMRId();
|
||||
unsigned int colorCode = m_conf.getDMRColorCode();
|
||||
unsigned int timeout = m_conf.getTimeout();
|
||||
|
||||
LogInfo("DMR Parameters");
|
||||
LogInfo(" Id: %u", id);
|
||||
LogInfo(" Color Code: %u", colorCode);
|
||||
LogInfo(" Timeout: %us", timeout);
|
||||
|
||||
dmr = new CDMRControl(id, colorCode, timeout, m_modem, m_dmrNetwork, m_display);
|
||||
}
|
||||
|
||||
CYSFEcho* ysf = NULL;
|
||||
if (m_ysfEnabled)
|
||||
ysf = new CYSFEcho(2U, 10000U);
|
||||
|
||||
unsigned char mode = MODE_IDLE;
|
||||
CTimer modeTimer(1000U, m_conf.getModeHang());
|
||||
|
||||
m_display->setIdle();
|
||||
|
||||
while (!m_killed) {
|
||||
unsigned char data[200U];
|
||||
unsigned int len;
|
||||
bool ret;
|
||||
|
||||
len = m_modem->readDStarData(data);
|
||||
if (dstar != NULL && len > 0U) {
|
||||
if (mode == MODE_IDLE && (data[0U] == TAG_HEADER || data[0U] == TAG_DATA)) {
|
||||
LogMessage("Mode set to D-Star");
|
||||
mode = MODE_DSTAR;
|
||||
m_display->setDStar();
|
||||
m_modem->setMode(MODE_DSTAR);
|
||||
modeTimer.start();
|
||||
}
|
||||
if (mode != MODE_DSTAR) {
|
||||
LogWarning("D-Star data received when in mode %u", mode);
|
||||
} else {
|
||||
if (data[0U] == TAG_HEADER || data[0U] == TAG_DATA || data[0U] == TAG_EOT) {
|
||||
dstar->writeData(data, len);
|
||||
modeTimer.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
len = m_modem->readDMRData1(data);
|
||||
if (dmr != NULL && len > 0U) {
|
||||
if (mode == MODE_IDLE) {
|
||||
bool ret = dmr->processWakeup(data);
|
||||
if (ret) {
|
||||
LogMessage("Mode set to DMR");
|
||||
mode = MODE_DMR;
|
||||
m_display->setDMR();
|
||||
// This sets the mode to DMR within the modem
|
||||
m_modem->writeDMRStart(true);
|
||||
modeTimer.start();
|
||||
}
|
||||
} else if (mode == MODE_DMR) {
|
||||
dmr->writeModemSlot1(data);
|
||||
modeTimer.start();
|
||||
} else {
|
||||
LogWarning("DMR data received when in mode %u", mode);
|
||||
}
|
||||
}
|
||||
|
||||
len = m_modem->readDMRData2(data);
|
||||
if (dmr != NULL && len > 0U) {
|
||||
if (mode == MODE_IDLE) {
|
||||
bool ret = dmr->processWakeup(data);
|
||||
if (ret) {
|
||||
LogMessage("Mode set to DMR");
|
||||
mode = MODE_DMR;
|
||||
m_display->setDMR();
|
||||
// This sets the mode to DMR within the modem
|
||||
m_modem->writeDMRStart(true);
|
||||
modeTimer.start();
|
||||
}
|
||||
} else if (mode == MODE_DMR) {
|
||||
dmr->writeModemSlot2(data);
|
||||
modeTimer.start();
|
||||
} else {
|
||||
LogWarning("DMR data received when in mode %u", mode);
|
||||
}
|
||||
}
|
||||
|
||||
len = m_modem->readYSFData(data);
|
||||
if (ysf != NULL && len > 0U) {
|
||||
if (mode == MODE_IDLE && data[0U] == TAG_DATA) {
|
||||
LogMessage("Mode set to System Fusion");
|
||||
mode = MODE_YSF;
|
||||
m_display->setFusion();
|
||||
m_modem->setMode(MODE_YSF);
|
||||
modeTimer.start();
|
||||
}
|
||||
if (mode != MODE_YSF) {
|
||||
LogWarning("System Fusion data received when in mode %u", mode);
|
||||
} else {
|
||||
if (data[0U] == TAG_DATA) {
|
||||
data[1U] = 0x00U; // FICH digest
|
||||
ysf->writeData(data, len);
|
||||
modeTimer.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (modeTimer.isRunning() && modeTimer.hasExpired()) {
|
||||
LogMessage("Mode set to Idle");
|
||||
|
||||
if (mode == MODE_DMR)
|
||||
m_modem->writeDMRStart(false);
|
||||
|
||||
mode = MODE_IDLE;
|
||||
m_display->setIdle();
|
||||
m_modem->setMode(MODE_IDLE);
|
||||
modeTimer.stop();
|
||||
}
|
||||
|
||||
if (dstar != NULL) {
|
||||
ret = dstar->hasData();
|
||||
if (ret) {
|
||||
ret = m_modem->hasDStarSpace();
|
||||
if (ret) {
|
||||
len = dstar->readData(data);
|
||||
if (mode != MODE_DSTAR) {
|
||||
LogWarning("D-Star echo data received when in mode %u", mode);
|
||||
} else {
|
||||
m_modem->writeDStarData(data, len);
|
||||
modeTimer.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dmr != NULL) {
|
||||
ret = m_modem->hasDMRSpace1();
|
||||
if (ret) {
|
||||
len = dmr->readModemSlot1(data);
|
||||
if (len > 0U && mode == MODE_IDLE) {
|
||||
m_display->setDMR();
|
||||
mode = MODE_DMR;
|
||||
}
|
||||
if (len > 0U && mode == MODE_DMR) {
|
||||
m_modem->writeDMRData1(data, len);
|
||||
modeTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
ret = m_modem->hasDMRSpace2();
|
||||
if (ret) {
|
||||
len = dmr->readModemSlot2(data);
|
||||
if (len > 0U && mode == MODE_IDLE) {
|
||||
m_display->setDMR();
|
||||
mode = MODE_DMR;
|
||||
}
|
||||
if (len > 0U && mode == MODE_DMR) {
|
||||
m_modem->writeDMRData2(data, len);
|
||||
modeTimer.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ysf != NULL) {
|
||||
ret = ysf->hasData();
|
||||
if (ret) {
|
||||
ret = m_modem->hasYSFSpace();
|
||||
if (ret) {
|
||||
len = ysf->readData(data);
|
||||
if (mode != MODE_YSF) {
|
||||
LogWarning("System Fusion echo data received when in mode %u", mode);
|
||||
} else {
|
||||
m_modem->writeYSFData(data, len);
|
||||
modeTimer.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int ms = stopWatch.elapsed();
|
||||
m_modem->clock(ms);
|
||||
modeTimer.clock(ms);
|
||||
if (dstar != NULL)
|
||||
dstar->clock(ms);
|
||||
if (dmr != NULL)
|
||||
dmr->clock(ms);
|
||||
if (ysf != NULL)
|
||||
ysf->clock(ms);
|
||||
stopWatch.start();
|
||||
|
||||
if (ms < 5U) {
|
||||
#if defined(WIN32)
|
||||
::Sleep(5UL); // 5ms
|
||||
#else
|
||||
::usleep(5000); // 5ms
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
LogMessage("MMDVMHost is exiting on receipt of SIGHUP1");
|
||||
|
||||
m_display->setIdle();
|
||||
|
||||
m_modem->close();
|
||||
delete m_modem;
|
||||
|
||||
m_display->close();
|
||||
delete m_display;
|
||||
|
||||
if (m_dmrNetwork != NULL) {
|
||||
m_dmrNetwork->close();
|
||||
delete m_dmrNetwork;
|
||||
}
|
||||
|
||||
delete dstar;
|
||||
delete dmr;
|
||||
delete ysf;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CMMDVMHost::createModem()
|
||||
{
|
||||
std::string port = m_conf.getModemPort();
|
||||
bool rxInvert = m_conf.getModemRXInvert();
|
||||
bool txInvert = m_conf.getModemTXInvert();
|
||||
bool pttInvert = m_conf.getModemPTTInvert();
|
||||
unsigned int txDelay = m_conf.getModemTXDelay();
|
||||
unsigned int rxLevel = m_conf.getModemRXLevel();
|
||||
unsigned int txLevel = m_conf.getModemTXLevel();
|
||||
bool debug = m_conf.getModemDebug();
|
||||
unsigned int colorCode = m_conf.getDMRColorCode();
|
||||
|
||||
LogInfo("Modem Parameters");
|
||||
LogInfo(" Port: %s", port.c_str());
|
||||
LogInfo(" RX Invert: %s", rxInvert ? "yes" : "no");
|
||||
LogInfo(" TX Invert: %s", txInvert ? "yes" : "no");
|
||||
LogInfo(" PTT Invert: %s", pttInvert ? "yes" : "no");
|
||||
LogInfo(" TX Delay: %u", txDelay);
|
||||
LogInfo(" RX Level: %u", rxLevel);
|
||||
LogInfo(" TX Level: %u", txLevel);
|
||||
|
||||
m_modem = new CModem(port, rxInvert, txInvert, pttInvert, txDelay, rxLevel, txLevel, debug);
|
||||
m_modem->setModeParams(m_dstarEnabled, m_dmrEnabled, m_ysfEnabled);
|
||||
m_modem->setDMRParams(colorCode);
|
||||
|
||||
bool ret = m_modem->open();
|
||||
if (!ret) {
|
||||
delete m_modem;
|
||||
m_modem = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMMDVMHost::createDMRNetwork()
|
||||
{
|
||||
if (!m_conf.getDMRNetworkEnabled())
|
||||
return false;
|
||||
|
||||
std::string address = m_conf.getDMRNetworkAddress();
|
||||
unsigned int port = m_conf.getDMRNetworkPort();
|
||||
unsigned int id = m_conf.getDMRId();
|
||||
std::string password = m_conf.getDMRNetworkPassword();
|
||||
bool debug = m_conf.getDMRNetworkDebug();
|
||||
|
||||
LogInfo("DMR Network Parameters");
|
||||
LogInfo(" Address: %s", address.c_str());
|
||||
LogInfo(" Port: %u", port);
|
||||
|
||||
m_dmrNetwork = new CHomebrewDMRIPSC(address, port, id, password, VERSION, "MMDVMHost", debug);
|
||||
|
||||
std::string callsign = m_conf.getCallsign();
|
||||
unsigned int rxFrequency = m_conf.getRxFrequency();
|
||||
unsigned int txFrequency = m_conf.getTxFrequency();
|
||||
unsigned int power = m_conf.getPower();
|
||||
unsigned int colorCode = m_conf.getDMRColorCode();
|
||||
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();
|
||||
|
||||
LogInfo("Info Parameters");
|
||||
LogInfo(" Callsign: %s", callsign.c_str());
|
||||
LogInfo(" RX Frequency: %uHz", rxFrequency);
|
||||
LogInfo(" TX Frequency: %uHz", txFrequency);
|
||||
LogInfo(" Power: %uW", power);
|
||||
LogInfo(" Latitude: %fdeg N", latitude);
|
||||
LogInfo(" Longitude: %fdeg E", longitude);
|
||||
LogInfo(" Height: %um", height);
|
||||
LogInfo(" Location: \"%s\"", location.c_str());
|
||||
LogInfo(" Description: \"%s\"", description.c_str());
|
||||
LogInfo(" URL: \"%s\"", url.c_str());
|
||||
|
||||
m_dmrNetwork->setConfig(callsign, rxFrequency, txFrequency, power, colorCode, latitude, longitude, height, location, description, url);
|
||||
|
||||
bool ret = m_dmrNetwork->open();
|
||||
if (!ret) {
|
||||
delete m_dmrNetwork;
|
||||
m_dmrNetwork = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CMMDVMHost::readParams()
|
||||
{
|
||||
m_dstarEnabled = m_conf.getDStarEnabled();
|
||||
m_dmrEnabled = m_conf.getDMREnabled();
|
||||
m_ysfEnabled = m_conf.getFusionEnabled();
|
||||
|
||||
if (!m_conf.getDuplex() && m_dmrEnabled) {
|
||||
LogWarning("DMR operation disabled because system is not duplex");
|
||||
m_dmrEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
void CMMDVMHost::createDisplay()
|
||||
{
|
||||
std::string type = m_conf.getDisplay();
|
||||
|
||||
LogInfo("Display Parameters");
|
||||
LogInfo(" Type: %s", type.c_str());
|
||||
|
||||
if (type == "TFT Serial") {
|
||||
std::string port = m_conf.getTFTSerialPort();
|
||||
|
||||
LogInfo(" Port: %s", port.c_str());
|
||||
|
||||
m_display = new CTFTSerial(port);
|
||||
} else {
|
||||
m_display = new CNullDisplay;
|
||||
}
|
||||
|
||||
bool ret = m_display->open();
|
||||
if (!ret) {
|
||||
delete m_display;
|
||||
m_display = new CNullDisplay;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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(MMDVMHOST_H)
|
||||
#define MMDVMHOST_H
|
||||
|
||||
#include "HomebrewDMRIPSC.h"
|
||||
#include "Display.h"
|
||||
#include "Modem.h"
|
||||
#include "Conf.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class CMMDVMHost
|
||||
{
|
||||
public:
|
||||
CMMDVMHost(const std::string& confFile);
|
||||
~CMMDVMHost();
|
||||
|
||||
int run();
|
||||
|
||||
private:
|
||||
CConf m_conf;
|
||||
CModem* m_modem;
|
||||
CHomebrewDMRIPSC* m_dmrNetwork;
|
||||
IDisplay* m_display;
|
||||
bool m_dstarEnabled;
|
||||
bool m_dmrEnabled;
|
||||
bool m_ysfEnabled;
|
||||
|
||||
void readParams();
|
||||
bool createModem();
|
||||
bool createDMRNetwork();
|
||||
void createDisplay();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.24720.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MMDVMHost", "MMDVMHost.vcxproj", "{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Debug|x64.Build.0 = Debug|x64
|
||||
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Debug|x86.Build.0 = Debug|Win32
|
||||
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Release|x64.ActiveCfg = Release|x64
|
||||
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Release|x64.Build.0 = Release|x64
|
||||
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Release|x86.ActiveCfg = Release|Win32
|
||||
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,228 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>MMDVMHost</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="BPTC19696.h" />
|
||||
<ClInclude Include="Conf.h" />
|
||||
<ClInclude Include="CRC.h" />
|
||||
<ClInclude Include="CSBK.h" />
|
||||
<ClInclude Include="Defines.h" />
|
||||
<ClInclude Include="Display.h" />
|
||||
<ClInclude Include="DMRControl.h" />
|
||||
<ClInclude Include="DMRData.h" />
|
||||
<ClInclude Include="DMRDefines.h" />
|
||||
<ClInclude Include="DMRSlot.h" />
|
||||
<ClInclude Include="DMRSync.h" />
|
||||
<ClInclude Include="DStarDefines.h" />
|
||||
<ClInclude Include="DStarEcho.h" />
|
||||
<ClInclude Include="EMB.h" />
|
||||
<ClInclude Include="EmbeddedLC.h" />
|
||||
<ClInclude Include="FullLC.h" />
|
||||
<ClInclude Include="Golay2087.h" />
|
||||
<ClInclude Include="Golay24128.h" />
|
||||
<ClInclude Include="Hamming.h" />
|
||||
<ClInclude Include="HomebrewDMRIPSC.h" />
|
||||
<ClInclude Include="LC.h" />
|
||||
<ClInclude Include="Log.h" />
|
||||
<ClInclude Include="MMDVMHost.h" />
|
||||
<ClInclude Include="Modem.h" />
|
||||
<ClInclude Include="NullDisplay.h" />
|
||||
<ClInclude Include="QR1676.h" />
|
||||
<ClInclude Include="RingBuffer.h" />
|
||||
<ClInclude Include="RS129.h" />
|
||||
<ClInclude Include="SerialController.h" />
|
||||
<ClInclude Include="SHA256.h" />
|
||||
<ClInclude Include="ShortLC.h" />
|
||||
<ClInclude Include="SlotType.h" />
|
||||
<ClInclude Include="StopWatch.h" />
|
||||
<ClInclude Include="TFTSerial.h" />
|
||||
<ClInclude Include="Timer.h" />
|
||||
<ClInclude Include="UDPSocket.h" />
|
||||
<ClInclude Include="Utils.h" />
|
||||
<ClInclude Include="YSFDefines.h" />
|
||||
<ClInclude Include="YSFEcho.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="BPTC19696.cpp" />
|
||||
<ClCompile Include="Conf.cpp" />
|
||||
<ClCompile Include="CRC.cpp" />
|
||||
<ClCompile Include="CSBK.cpp" />
|
||||
<ClCompile Include="Display.cpp" />
|
||||
<ClCompile Include="DMRControl.cpp" />
|
||||
<ClCompile Include="DMRData.cpp" />
|
||||
<ClCompile Include="DMRSlot.cpp" />
|
||||
<ClCompile Include="DMRSync.cpp" />
|
||||
<ClCompile Include="DStarEcho.cpp" />
|
||||
<ClCompile Include="EMB.cpp" />
|
||||
<ClCompile Include="EmbeddedLC.cpp" />
|
||||
<ClCompile Include="FullLC.cpp" />
|
||||
<ClCompile Include="Golay2087.cpp" />
|
||||
<ClCompile Include="Golay24128.cpp" />
|
||||
<ClCompile Include="Hamming.cpp" />
|
||||
<ClCompile Include="HomebrewDMRIPSC.cpp" />
|
||||
<ClCompile Include="LC.cpp" />
|
||||
<ClCompile Include="Log.cpp" />
|
||||
<ClCompile Include="MMDVMHost.cpp" />
|
||||
<ClCompile Include="Modem.cpp" />
|
||||
<ClCompile Include="NullDisplay.cpp" />
|
||||
<ClCompile Include="QR1676.cpp" />
|
||||
<ClCompile Include="RS129.cpp" />
|
||||
<ClCompile Include="SerialController.cpp" />
|
||||
<ClCompile Include="SHA256.cpp" />
|
||||
<ClCompile Include="ShortLC.cpp" />
|
||||
<ClCompile Include="SlotType.cpp" />
|
||||
<ClCompile Include="StopWatch.cpp" />
|
||||
<ClCompile Include="TFTSerial.cpp" />
|
||||
<ClCompile Include="Timer.cpp" />
|
||||
<ClCompile Include="UDPSocket.cpp" />
|
||||
<ClCompile Include="Utils.cpp" />
|
||||
<ClCompile Include="YSFEcho.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -0,0 +1,236 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="BPTC19696.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Conf.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CRC.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CSBK.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Defines.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Display.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DMRControl.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DMRData.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DMRDefines.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DMRSlot.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DMRSync.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DStarDefines.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DStarEcho.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="EMB.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="EmbeddedLC.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FullLC.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Golay2087.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Golay24128.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Hamming.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HomebrewDMRIPSC.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="LC.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Log.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MMDVMHost.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Modem.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NullDisplay.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="QR1676.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RingBuffer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RS129.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SerialController.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SHA256.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ShortLC.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SlotType.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="StopWatch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TFTSerial.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Timer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="UDPSocket.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Utils.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="YSFDefines.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="YSFEcho.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="BPTC19696.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Conf.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CRC.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CSBK.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Display.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DMRControl.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DMRData.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DMRSlot.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DMRSync.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DStarEcho.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="EMB.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="EmbeddedLC.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FullLC.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Golay2087.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Golay24128.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Hamming.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HomebrewDMRIPSC.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LC.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Log.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MMDVMHost.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Modem.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NullDisplay.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="QR1676.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="RS129.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SerialController.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SHA256.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ShortLC.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SlotType.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="StopWatch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TFTSerial.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Timer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="UDPSocket.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Utils.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="YSFEcho.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,120 @@
|
|||
CC = g++
|
||||
CFLAGS = -O2 -Wall -std=c++11
|
||||
LIBS =
|
||||
LDFLAGS =
|
||||
|
||||
all: MMDVMHost
|
||||
|
||||
MMDVMHost: BPTC19696.o Conf.o CRC.o CSBK.o Display.o DMRControl.o DMRData.o DMRSlot.o DMRSync.o DStarEcho.o EMB.o EmbeddedLC.o FullLC.o Golay2087.o Golay24128.o \
|
||||
Hamming.o HomebrewDMRIPSC.o LC.o Log.o MMDVMHost.o Modem.o NullDisplay.o QR1676.o RS129.o SerialController.o SHA256.o ShortLC.o SlotType.o StopWatch.o \
|
||||
TFTSerial.o Timer.o UDPSocket.o Utils.o YSFEcho.o
|
||||
$(CC) $(LDFLAGS) -o MMDVMHost BPTC19696.o Conf.o CRC.o CSBK.o Display.o DMRControl.o DMRData.o DMRSlot.o DMRSync.o DStarEcho.o EMB.o EmbeddedLC.o FullLC.o \
|
||||
Golay2087.o Golay24128.o Hamming.o HomebrewDMRIPSC.o LC.o Log.o MMDVMHost.o Modem.o NullDisplay.o QR1676.o RS129.o SerialController.o SHA256.o ShortLC.o \
|
||||
SlotType.o StopWatch.o TFTSerial.o Timer.o UDPSocket.o Utils.o YSFEcho.o $(LIBS)
|
||||
|
||||
BPTC19696.o: BPTC19696.cpp BPTC19696.h Utils.h Hamming.h
|
||||
$(CC) $(CFLAGS) -c BPTC19696.cpp
|
||||
|
||||
Conf.o: Conf.cpp Conf.h Log.h
|
||||
$(CC) $(CFLAGS) -c Conf.cpp
|
||||
|
||||
CRC.o: CRC.cpp CRC.h Utils.h
|
||||
$(CC) $(CFLAGS) -c CRC.cpp
|
||||
|
||||
CSBK.o: CSBK.cpp CSBK.h Utils.h DMRDefines.h BPTC19696.h CRC.h Log.h
|
||||
$(CC) $(CFLAGS) -c CSBK.cpp
|
||||
|
||||
Display.o: Display.cpp Display.h
|
||||
$(CC) $(CFLAGS) -c Display.cpp
|
||||
|
||||
DMRControl.o: DMRControl.cpp DMRControl.h DMRSlot.h DMRData.h Modem.h HomebrewDMRIPSC.h Defines.h CSBK.h Log.h DIsplay.h
|
||||
$(CC) $(CFLAGS) -c DMRControl.cpp
|
||||
|
||||
DMRData.o: DMRData.cpp DMRData.h DMRDefines.h Utils.h Log.h
|
||||
$(CC) $(CFLAGS) -c DMRData.cpp
|
||||
|
||||
DMRSlot.o: DMRSlot.cpp DMRSlot.h DMRData.h Modem.h HomebrewDMRIPSC.h Defines.h Log.h EmbeddedLC.h RingBuffer.h Timer.h LC.h SlotType.h DMRSync.h FullLC.h \
|
||||
EMB.h CRC.h CSBK.h ShortLC.h Utils.h Display.h
|
||||
$(CC) $(CFLAGS) -c DMRSlot.cpp
|
||||
|
||||
DMRSync.o: DMRSync.cpp DMRSync.h DMRDefines.h
|
||||
$(CC) $(CFLAGS) -c DMRSync.cpp
|
||||
|
||||
DStarEcho.o: DStarEcho.cpp DStarEcho.h RingBuffer.h Timer.h
|
||||
$(CC) $(CFLAGS) -c DStarEcho.cpp
|
||||
|
||||
EMB.o: EMB.cpp EMB.h
|
||||
$(CC) $(CFLAGS) -c EMB.cpp
|
||||
|
||||
EmbeddedLC.o: EmbeddedLC.cpp EmbeddedLC.h CRC.h Utils.h LC.h Hamming.h Log.h
|
||||
$(CC) $(CFLAGS) -c EmbeddedLC.cpp
|
||||
|
||||
FullLC.o: FullLC.cpp FullLC.h BPTC19696.h LC.h SlotType.h Log.h DMRDefines.h RS129.h
|
||||
$(CC) $(CFLAGS) -c FullLC.cpp
|
||||
|
||||
Golay2087.o: Golay2087.cpp Golay2087.h
|
||||
$(CC) $(CFLAGS) -c Golay2087.cpp
|
||||
|
||||
Golay24128.o: Golay24128.cpp Golay24128.h
|
||||
$(CC) $(CFLAGS) -c Golay24128.cpp
|
||||
|
||||
Hamming.o: Hamming.cpp Hamming.h
|
||||
$(CC) $(CFLAGS) -c Hamming.cpp
|
||||
|
||||
HomebrewDMRIPSC.o: HomebrewDMRIPSC.cpp HomebrewDMRIPSC.h Log.h UDPSocket.h Timer.h DMRData.h RingBuffer.h Utils.h SHA256.h StopWatch.h
|
||||
$(CC) $(CFLAGS) -c HomebrewDMRIPSC.cpp
|
||||
|
||||
LC.o: LC.cpp LC.h Utils.h DMRDefines.h
|
||||
$(CC) $(CFLAGS) -c LC.cpp
|
||||
|
||||
Log.o: Log.cpp Log.h
|
||||
$(CC) $(CFLAGS) -c Log.cpp
|
||||
|
||||
MMDVMHost.o: MMDVMHost.cpp MMDVMHost.h Conf.h Log.h Version.h Modem.h StopWatch.h Defines.h DMRSync.h DStarEcho.h YSFEcho.h DMRControl.h HomebrewDMRIPSC.h \
|
||||
Display.h TFTSerial.h NullDisplay.h
|
||||
$(CC) $(CFLAGS) -c MMDVMHost.cpp
|
||||
|
||||
Modem.o: Modem.cpp Modem.h Log.h SerialController.h Timer.h RingBuffer.h Utils.o DMRDefines.h DStarDefines.h YSFDefines.h Defines.h
|
||||
$(CC) $(CFLAGS) -c Modem.cpp
|
||||
|
||||
NullDisplay.o: NullDisplay.cpp NullDisplay.h Display.h
|
||||
$(CC) $(CFLAGS) -c NullDisplay.cpp
|
||||
|
||||
QR1676.o: QR1676.cpp QR1676.h Log.h
|
||||
$(CC) $(CFLAGS) -c QR1676.cpp
|
||||
|
||||
RS129.o: RS129.cpp RS129.h
|
||||
$(CC) $(CFLAGS) -c RS129.cpp
|
||||
|
||||
SerialController.o: SerialController.cpp SerialController.h Log.h
|
||||
$(CC) $(CFLAGS) -c SerialController.cpp
|
||||
|
||||
SHA256.o: SHA256.cpp SHA256.h
|
||||
$(CC) $(CFLAGS) -c SHA256.cpp
|
||||
|
||||
ShortLC.o: ShortLC.cpp ShortLC.h Utils.h Hamming.h
|
||||
$(CC) $(CFLAGS) -c ShortLC.cpp
|
||||
|
||||
SlotType.o: SlotType.cpp SlotType.h Golay2087.h
|
||||
$(CC) $(CFLAGS) -c SlotType.cpp
|
||||
|
||||
StopWatch.o: StopWatch.cpp StopWatch.h
|
||||
$(CC) $(CFLAGS) -c StopWatch.cpp
|
||||
|
||||
TFTSerial.o: TFTSerial.cpp TFTSerial.h Display.h SerialController.h Log.h
|
||||
$(CC) $(CFLAGS) -c TFTSerial.cpp
|
||||
|
||||
Timer.o: Timer.cpp Timer.h
|
||||
$(CC) $(CFLAGS) -c Timer.cpp
|
||||
|
||||
UDPSocket.o: UDPSocket.cpp UDPSocket.h Log.h
|
||||
$(CC) $(CFLAGS) -c UDPSocket.cpp
|
||||
|
||||
Utils.o: Utils.cpp Utils.h Log.h
|
||||
$(CC) $(CFLAGS) -c Utils.cpp
|
||||
|
||||
YSFEcho.o: YSFEcho.cpp YSFEcho.h YSFDefines.h RingBuffer.h Timer.h
|
||||
$(CC) $(CFLAGS) -c YSFEcho.cpp
|
||||
|
||||
clean:
|
||||
$(RM) MMDVMHost *.o *.bak *~
|
|
@ -0,0 +1,884 @@
|
|||
/*
|
||||
* Copyright (C) 2011-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 "DStarDefines.h"
|
||||
#include "DMRDefines.h"
|
||||
#include "YSFDefines.h"
|
||||
#include "Defines.h"
|
||||
#include "Modem.h"
|
||||
#include "Utils.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cassert>
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <Windows.h>
|
||||
typedef unsigned int uint32_t;
|
||||
#else
|
||||
#include <cstdint>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
const unsigned char MMDVM_FRAME_START = 0xE0U;
|
||||
|
||||
const unsigned char MMDVM_GET_VERSION = 0x00U;
|
||||
const unsigned char MMDVM_GET_STATUS = 0x01U;
|
||||
const unsigned char MMDVM_SET_CONFIG = 0x02U;
|
||||
const unsigned char MMDVM_SET_MODE = 0x03U;
|
||||
|
||||
const unsigned char MMDVM_DSTAR_HEADER = 0x10U;
|
||||
const unsigned char MMDVM_DSTAR_DATA = 0x11U;
|
||||
const unsigned char MMDVM_DSTAR_LOST = 0x12U;
|
||||
const unsigned char MMDVM_DSTAR_EOT = 0x13U;
|
||||
|
||||
const unsigned char MMDVM_DMR_DATA1 = 0x18U;
|
||||
const unsigned char MMDVM_DMR_LOST1 = 0x19U;
|
||||
const unsigned char MMDVM_DMR_DATA2 = 0x1AU;
|
||||
const unsigned char MMDVM_DMR_LOST2 = 0x1BU;
|
||||
const unsigned char MMDVM_DMR_SHORTLC = 0x1CU;
|
||||
const unsigned char MMDVM_DMR_START = 0x1DU;
|
||||
|
||||
const unsigned char MMDVM_YSF_DATA = 0x20U;
|
||||
const unsigned char MMDVM_YSF_LOST = 0x21U;
|
||||
|
||||
const unsigned char MMDVM_ACK = 0x70U;
|
||||
const unsigned char MMDVM_NAK = 0x7FU;
|
||||
|
||||
const unsigned char MMDVM_DUMP = 0xF0U;
|
||||
const unsigned char MMDVM_DEBUG1 = 0xF1U;
|
||||
const unsigned char MMDVM_DEBUG2 = 0xF2U;
|
||||
const unsigned char MMDVM_DEBUG3 = 0xF3U;
|
||||
const unsigned char MMDVM_DEBUG4 = 0xF4U;
|
||||
const unsigned char MMDVM_DEBUG5 = 0xF5U;
|
||||
const unsigned char MMDVM_SAMPLES = 0xF8U;
|
||||
|
||||
const unsigned int MAX_RESPONSES = 30U;
|
||||
|
||||
const unsigned int BUFFER_LENGTH = 500U;
|
||||
|
||||
|
||||
CModem::CModem(const std::string& port, bool rxInvert, bool txInvert, bool pttInvert, unsigned int txDelay, unsigned int rxLevel, unsigned int txLevel, bool debug) :
|
||||
m_port(port),
|
||||
m_colorCode(0U),
|
||||
m_rxInvert(rxInvert),
|
||||
m_txInvert(txInvert),
|
||||
m_pttInvert(pttInvert),
|
||||
m_txDelay(txDelay),
|
||||
m_rxLevel(rxLevel),
|
||||
m_txLevel(txLevel),
|
||||
m_debug(debug),
|
||||
m_dstarEnabled(false),
|
||||
m_dmrEnabled(false),
|
||||
m_ysfEnabled(false),
|
||||
m_serial(port, SERIAL_115200, true),
|
||||
m_buffer(NULL),
|
||||
m_rxDStarData(1000U),
|
||||
m_txDStarData(1000U),
|
||||
m_rxDMRData1(1000U),
|
||||
m_rxDMRData2(1000U),
|
||||
m_txDMRData1(1000U),
|
||||
m_txDMRData2(1000U),
|
||||
m_rxYSFData(1000U),
|
||||
m_txYSFData(1000U),
|
||||
m_statusTimer(1000U, 0U, 100U),
|
||||
m_dstarSpace(0U),
|
||||
m_dmrSpace1(0U),
|
||||
m_dmrSpace2(0U),
|
||||
m_ysfSpace(0U),
|
||||
m_tx(false)
|
||||
{
|
||||
assert(!port.empty());
|
||||
|
||||
m_buffer = new unsigned char[BUFFER_LENGTH];
|
||||
}
|
||||
|
||||
CModem::~CModem()
|
||||
{
|
||||
delete[] m_buffer;
|
||||
}
|
||||
|
||||
void CModem::setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled)
|
||||
{
|
||||
m_dstarEnabled = dstarEnabled;
|
||||
m_dmrEnabled = dmrEnabled;
|
||||
m_ysfEnabled = ysfEnabled;
|
||||
}
|
||||
|
||||
void CModem::setDMRParams(unsigned int colorCode)
|
||||
{
|
||||
assert(colorCode < 16U);
|
||||
|
||||
m_colorCode = colorCode;
|
||||
}
|
||||
|
||||
bool CModem::open()
|
||||
{
|
||||
::LogMessage("Opening the MMDVM");
|
||||
|
||||
bool ret = m_serial.open();
|
||||
if (!ret)
|
||||
return false;
|
||||
|
||||
ret = readVersion();
|
||||
if (!ret) {
|
||||
m_serial.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = setConfig();
|
||||
if (!ret) {
|
||||
m_serial.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_statusTimer.start();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CModem::clock(unsigned int ms)
|
||||
{
|
||||
// Poll the modem status every 100ms
|
||||
m_statusTimer.clock(ms);
|
||||
if (m_statusTimer.hasExpired()) {
|
||||
readStatus();
|
||||
m_statusTimer.start();
|
||||
}
|
||||
|
||||
unsigned int length;
|
||||
RESP_TYPE_MMDVM type = getResponse(m_buffer, length);
|
||||
|
||||
if (type == RTM_TIMEOUT) {
|
||||
// Nothing to do
|
||||
} else if (type == RTM_ERROR) {
|
||||
LogError("Error when reading from the MMDVM");
|
||||
} else {
|
||||
// type == RTM_OK
|
||||
switch (m_buffer[2U]) {
|
||||
case MMDVM_DSTAR_HEADER: {
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "RX D-Star Header", m_buffer, length);
|
||||
|
||||
unsigned char data = length - 2U;
|
||||
m_rxDStarData.addData(&data, 1U);
|
||||
|
||||
data = TAG_HEADER;
|
||||
m_rxDStarData.addData(&data, 1U);
|
||||
|
||||
m_rxDStarData.addData(m_buffer + 3U, length - 3U);
|
||||
}
|
||||
break;
|
||||
|
||||
case MMDVM_DSTAR_DATA: {
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "RX D-Star Data", m_buffer, length);
|
||||
|
||||
unsigned char data = length - 2U;
|
||||
m_rxDStarData.addData(&data, 1U);
|
||||
|
||||
data = TAG_DATA;
|
||||
m_rxDStarData.addData(&data, 1U);
|
||||
|
||||
m_rxDStarData.addData(m_buffer + 3U, length - 3U);
|
||||
}
|
||||
break;
|
||||
|
||||
case MMDVM_DSTAR_LOST: {
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "RX D-Star Lost", m_buffer, length);
|
||||
|
||||
unsigned char data = 1U;
|
||||
m_rxDStarData.addData(&data, 1U);
|
||||
|
||||
data = TAG_LOST;
|
||||
m_rxDStarData.addData(&data, 1U);
|
||||
}
|
||||
break;
|
||||
|
||||
case MMDVM_DSTAR_EOT: {
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "RX D-Star EOT", m_buffer, length);
|
||||
|
||||
unsigned char data = 1U;
|
||||
m_rxDStarData.addData(&data, 1U);
|
||||
|
||||
data = TAG_EOT;
|
||||
m_rxDStarData.addData(&data, 1U);
|
||||
}
|
||||
break;
|
||||
|
||||
case MMDVM_DMR_DATA1: {
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "RX DMR Data 1", m_buffer, length);
|
||||
|
||||
unsigned char data = length - 2U;
|
||||
m_rxDMRData1.addData(&data, 1U);
|
||||
|
||||
if (m_buffer[3U] == (DMR_SYNC_DATA | DT_TERMINATOR_WITH_LC))
|
||||
data = TAG_EOT;
|
||||
else
|
||||
data = TAG_DATA;
|
||||
m_rxDMRData1.addData(&data, 1U);
|
||||
|
||||
m_rxDMRData1.addData(m_buffer + 3U, length - 3U);
|
||||
}
|
||||
break;
|
||||
|
||||
case MMDVM_DMR_DATA2: {
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "RX DMR Data 2", m_buffer, length);
|
||||
|
||||
unsigned char data = length - 2U;
|
||||
m_rxDMRData2.addData(&data, 1U);
|
||||
|
||||
if (m_buffer[3U] == (DMR_SYNC_DATA | DT_TERMINATOR_WITH_LC))
|
||||
data = TAG_EOT;
|
||||
else
|
||||
data = TAG_DATA;
|
||||
m_rxDMRData2.addData(&data, 1U);
|
||||
|
||||
m_rxDMRData2.addData(m_buffer + 3U, length - 3U);
|
||||
}
|
||||
break;
|
||||
|
||||
case MMDVM_DMR_LOST1: {
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "RX DMR Lost 1", m_buffer, length);
|
||||
|
||||
unsigned char data = 1U;
|
||||
m_rxDMRData1.addData(&data, 1U);
|
||||
|
||||
data = TAG_LOST;
|
||||
m_rxDMRData1.addData(&data, 1U);
|
||||
}
|
||||
break;
|
||||
|
||||
case MMDVM_DMR_LOST2: {
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "RX DMR Lost 2", m_buffer, length);
|
||||
|
||||
unsigned char data = 1U;
|
||||
m_rxDMRData2.addData(&data, 1U);
|
||||
|
||||
data = TAG_LOST;
|
||||
m_rxDMRData2.addData(&data, 1U);
|
||||
}
|
||||
break;
|
||||
|
||||
case MMDVM_YSF_DATA: {
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "RX YSF Data", m_buffer, length);
|
||||
|
||||
unsigned char data = length - 2U;
|
||||
m_rxYSFData.addData(&data, 1U);
|
||||
|
||||
if ((m_buffer[3U] & (YSF_CKSUM_OK | YSF_FI_MASK)) == (YSF_CKSUM_OK | YSF_DT_TERMINATOR_CHANNEL))
|
||||
data = TAG_EOT;
|
||||
else
|
||||
data = TAG_DATA;
|
||||
m_rxYSFData.addData(&data, 1U);
|
||||
|
||||
m_rxYSFData.addData(m_buffer + 3U, length - 3U);
|
||||
}
|
||||
break;
|
||||
|
||||
case MMDVM_YSF_LOST: {
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "RX YSF Lost", m_buffer, length);
|
||||
|
||||
unsigned char data = 1U;
|
||||
m_rxYSFData.addData(&data, 1U);
|
||||
|
||||
data = TAG_LOST;
|
||||
m_rxYSFData.addData(&data, 1U);
|
||||
}
|
||||
break;
|
||||
|
||||
case MMDVM_GET_STATUS: {
|
||||
// if (m_debug)
|
||||
// CUtils::dump(1U, "GET_STATUS", m_buffer, length);
|
||||
|
||||
m_tx = (m_buffer[5U] & 0x01U) == 0x01U;
|
||||
|
||||
bool adcOverflow = (m_buffer[5U] & 0x02U) == 0x02U;
|
||||
if (adcOverflow)
|
||||
LogWarning("MMDVM ADC levels have overflowed");
|
||||
|
||||
m_dstarSpace = m_buffer[6U];
|
||||
m_dmrSpace1 = m_buffer[7U];
|
||||
m_dmrSpace2 = m_buffer[8U];
|
||||
m_ysfSpace = m_buffer[9U];
|
||||
// LogMessage("tx=%d, space=%u,%u,%u,%u", int(m_tx), m_dstarSpace, m_dmrSpace1, m_dmrSpace2, m_ysfSpace);
|
||||
}
|
||||
break;
|
||||
|
||||
// These should not be received, but don't complain if we do
|
||||
case MMDVM_GET_VERSION:
|
||||
case MMDVM_ACK:
|
||||
break;
|
||||
|
||||
case MMDVM_NAK:
|
||||
LogWarning("Received a NAK from the MMDVM, command = 0x%02X, reason = %u", m_buffer[3U], m_buffer[4U]);
|
||||
break;
|
||||
|
||||
case MMDVM_DEBUG1:
|
||||
case MMDVM_DEBUG2:
|
||||
case MMDVM_DEBUG3:
|
||||
case MMDVM_DEBUG4:
|
||||
case MMDVM_DEBUG5:
|
||||
printDebug();
|
||||
break;
|
||||
|
||||
case MMDVM_SAMPLES:
|
||||
// printSamples();
|
||||
break;
|
||||
|
||||
default:
|
||||
LogMessage("Unknown message, type: %02X", m_buffer[2U]);
|
||||
CUtils::dump("Buffer dump", m_buffer, length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_dstarSpace > 1U && !m_txDStarData.isEmpty()) {
|
||||
unsigned char len = 0U;
|
||||
m_txDStarData.getData(&len, 1U);
|
||||
m_txDStarData.getData(m_buffer, len);
|
||||
|
||||
if (m_debug) {
|
||||
if (len > (DSTAR_FRAME_LENGTH_BYTES + 3U))
|
||||
CUtils::dump(1U, "TX D-Star Header", m_buffer, len);
|
||||
else if (len == (DSTAR_FRAME_LENGTH_BYTES + 3U))
|
||||
CUtils::dump(1U, "TX D-Star Data", m_buffer, len);
|
||||
else
|
||||
CUtils::dump(1U, "TX D-Star EOT", m_buffer, len);
|
||||
}
|
||||
|
||||
int ret = m_serial.write(m_buffer, len);
|
||||
if (ret != int(len))
|
||||
LogWarning("Error when writing D-Star data to the MMDVM");
|
||||
|
||||
// Headers take four slots in the queues in the modem
|
||||
if (len > (DSTAR_FRAME_LENGTH_BYTES + 3U))
|
||||
m_dstarSpace -= 4U;
|
||||
else
|
||||
m_dstarSpace -= 1U;
|
||||
}
|
||||
|
||||
if (m_dmrSpace1 > 1U && !m_txDMRData1.isEmpty()) {
|
||||
unsigned char len = 0U;
|
||||
m_txDMRData1.getData(&len, 1U);
|
||||
m_txDMRData1.getData(m_buffer, len);
|
||||
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "TX DMR Data 1", m_buffer, len);
|
||||
|
||||
int ret = m_serial.write(m_buffer, len);
|
||||
if (ret != int(len))
|
||||
LogWarning("Error when writing DMR data to the MMDVM");
|
||||
|
||||
m_dmrSpace1--;
|
||||
}
|
||||
|
||||
if (m_dmrSpace2 > 1U && !m_txDMRData2.isEmpty()) {
|
||||
unsigned char len = 0U;
|
||||
m_txDMRData2.getData(&len, 1U);
|
||||
m_txDMRData2.getData(m_buffer, len);
|
||||
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "TX DMR Data 2", m_buffer, len);
|
||||
|
||||
int ret = m_serial.write(m_buffer, len);
|
||||
if (ret != int(len))
|
||||
LogWarning("Error when writing DMR data to the MMDVM");
|
||||
|
||||
m_dmrSpace2--;
|
||||
}
|
||||
|
||||
if (m_ysfSpace > 1U && !m_txYSFData.isEmpty()) {
|
||||
unsigned char len = 0U;
|
||||
m_txYSFData.getData(&len, 1U);
|
||||
m_txYSFData.getData(m_buffer, len);
|
||||
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "TX YSF Data", m_buffer, len);
|
||||
|
||||
int ret = m_serial.write(m_buffer, len);
|
||||
if (ret != int(len))
|
||||
LogWarning("Error when writing YSF data to the MMDVM");
|
||||
|
||||
m_ysfSpace--;
|
||||
}
|
||||
}
|
||||
|
||||
void CModem::close()
|
||||
{
|
||||
::LogMessage("Closing the MMDVM");
|
||||
|
||||
delete[] m_buffer;
|
||||
|
||||
m_serial.close();
|
||||
}
|
||||
|
||||
unsigned int CModem::readDStarData(unsigned char* data)
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
if (m_rxDStarData.isEmpty())
|
||||
return 0U;
|
||||
|
||||
unsigned char len = 0U;
|
||||
m_rxDStarData.getData(&len, 1U);
|
||||
m_rxDStarData.getData(data, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
unsigned int CModem::readDMRData1(unsigned char* data)
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
if (m_rxDMRData1.isEmpty())
|
||||
return 0U;
|
||||
|
||||
unsigned char len = 0U;
|
||||
m_rxDMRData1.getData(&len, 1U);
|
||||
m_rxDMRData1.getData(data, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
unsigned int CModem::readDMRData2(unsigned char* data)
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
if (m_rxDMRData2.isEmpty())
|
||||
return 0U;
|
||||
|
||||
unsigned char len = 0U;
|
||||
m_rxDMRData2.getData(&len, 1U);
|
||||
m_rxDMRData2.getData(data, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
unsigned int CModem::readYSFData(unsigned char* data)
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
if (m_rxYSFData.isEmpty())
|
||||
return 0U;
|
||||
|
||||
unsigned char len = 0U;
|
||||
m_rxYSFData.getData(&len, 1U);
|
||||
m_rxYSFData.getData(data, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
bool CModem::hasDStarSpace() const
|
||||
{
|
||||
unsigned int space = m_txDStarData.freeSpace() / (DSTAR_FRAME_LENGTH_BYTES + 4U);
|
||||
|
||||
return space > 1U;
|
||||
}
|
||||
|
||||
bool CModem::writeDStarData(const unsigned char* data, unsigned int length)
|
||||
{
|
||||
assert(data != NULL);
|
||||
assert(length > 0U);
|
||||
|
||||
unsigned char buffer[50U];
|
||||
|
||||
buffer[0U] = MMDVM_FRAME_START;
|
||||
buffer[1U] = length + 2U;
|
||||
|
||||
switch (data[0U]) {
|
||||
case TAG_HEADER: buffer[2U] = MMDVM_DSTAR_HEADER; break;
|
||||
case TAG_DATA: buffer[2U] = MMDVM_DSTAR_DATA; break;
|
||||
case TAG_EOT: buffer[2U] = MMDVM_DSTAR_EOT; break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
::memcpy(buffer + 3U, data + 1U, length - 1U);
|
||||
|
||||
unsigned char len = length + 2U;
|
||||
m_txDStarData.addData(&len, 1U);
|
||||
m_txDStarData.addData(buffer, len);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CModem::hasDMRSpace1() const
|
||||
{
|
||||
unsigned int space = m_txDMRData1.freeSpace() / (DMR_FRAME_LENGTH_BYTES + 4U);
|
||||
|
||||
return space > 1U;
|
||||
}
|
||||
|
||||
bool CModem::hasDMRSpace2() const
|
||||
{
|
||||
unsigned int space = m_txDMRData2.freeSpace() / (DMR_FRAME_LENGTH_BYTES + 4U);
|
||||
|
||||
return space > 1U;
|
||||
}
|
||||
|
||||
bool CModem::writeDMRData1(const unsigned char* data, unsigned int length)
|
||||
{
|
||||
assert(data != NULL);
|
||||
assert(length > 0U);
|
||||
|
||||
if (data[0U] != TAG_DATA && data[0U] != TAG_EOT)
|
||||
return false;
|
||||
|
||||
unsigned char buffer[40U];
|
||||
|
||||
buffer[0U] = MMDVM_FRAME_START;
|
||||
buffer[1U] = length + 2U;
|
||||
buffer[2U] = MMDVM_DMR_DATA1;
|
||||
|
||||
::memcpy(buffer + 3U, data + 1U, length - 1U);
|
||||
|
||||
unsigned char len = length + 2U;
|
||||
m_txDMRData1.addData(&len, 1U);
|
||||
m_txDMRData1.addData(buffer, len);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CModem::writeDMRData2(const unsigned char* data, unsigned int length)
|
||||
{
|
||||
assert(data != NULL);
|
||||
assert(length > 0U);
|
||||
|
||||
if (data[0U] != TAG_DATA && data[0U] != TAG_EOT)
|
||||
return false;
|
||||
|
||||
unsigned char buffer[40U];
|
||||
|
||||
buffer[0U] = MMDVM_FRAME_START;
|
||||
buffer[1U] = length + 2U;
|
||||
buffer[2U] = MMDVM_DMR_DATA2;
|
||||
|
||||
::memcpy(buffer + 3U, data + 1U, length - 1U);
|
||||
|
||||
unsigned char len = length + 2U;
|
||||
m_txDMRData2.addData(&len, 1U);
|
||||
m_txDMRData2.addData(buffer, len);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CModem::hasYSFSpace() const
|
||||
{
|
||||
unsigned int space = m_txYSFData.freeSpace() / (YSF_FRAME_LENGTH_BYTES + 4U);
|
||||
|
||||
return space > 1U;
|
||||
}
|
||||
|
||||
bool CModem::writeYSFData(const unsigned char* data, unsigned int length)
|
||||
{
|
||||
assert(data != NULL);
|
||||
assert(length > 0U);
|
||||
|
||||
if (data[0U] != TAG_DATA && data[0U] != TAG_EOT)
|
||||
return false;
|
||||
|
||||
unsigned char buffer[130U];
|
||||
|
||||
buffer[0U] = MMDVM_FRAME_START;
|
||||
buffer[1U] = length + 2U;
|
||||
buffer[2U] = MMDVM_YSF_DATA;
|
||||
|
||||
::memcpy(buffer + 3U, data + 1U, length - 1U);
|
||||
|
||||
unsigned char len = length + 2U;
|
||||
m_txYSFData.addData(&len, 1U);
|
||||
m_txYSFData.addData(buffer, len);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CModem::readVersion()
|
||||
{
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
::Sleep(2000UL); // 2s
|
||||
#else
|
||||
::sleep(2); // 2s
|
||||
#endif
|
||||
|
||||
for (unsigned int i = 0U; i < 6U; i++) {
|
||||
unsigned char buffer[3U];
|
||||
|
||||
buffer[0U] = MMDVM_FRAME_START;
|
||||
buffer[1U] = 3U;
|
||||
buffer[2U] = MMDVM_GET_VERSION;
|
||||
|
||||
// CUtils::dump("Written", buffer, 3U);
|
||||
|
||||
int ret = m_serial.write(buffer, 3U);
|
||||
if (ret != 3)
|
||||
return false;
|
||||
|
||||
for (unsigned int count = 0U; count < MAX_RESPONSES; count++) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
::Sleep(10UL);
|
||||
#else
|
||||
::usleep(10000UL);
|
||||
#endif
|
||||
unsigned int length;
|
||||
RESP_TYPE_MMDVM resp = getResponse(m_buffer, length);
|
||||
if (resp == RTM_OK && m_buffer[2U] == MMDVM_GET_VERSION) {
|
||||
LogInfo("MMDVM protocol version: %u, description: %.*s", m_buffer[3U], length - 4U, m_buffer + 4U);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
::Sleep(1000UL); // 1s
|
||||
#else
|
||||
::sleep(1UL); // 1s
|
||||
#endif
|
||||
}
|
||||
|
||||
LogError("Unable to read the firmware version after six attempts");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CModem::readStatus()
|
||||
{
|
||||
unsigned char buffer[3U];
|
||||
|
||||
buffer[0U] = MMDVM_FRAME_START;
|
||||
buffer[1U] = 3U;
|
||||
buffer[2U] = MMDVM_GET_STATUS;
|
||||
|
||||
return m_serial.write(buffer, 3U) == 3;
|
||||
}
|
||||
|
||||
bool CModem::setConfig()
|
||||
{
|
||||
unsigned char buffer[10U];
|
||||
|
||||
buffer[0U] = MMDVM_FRAME_START;
|
||||
|
||||
buffer[1U] = 10U;
|
||||
|
||||
buffer[2U] = MMDVM_SET_CONFIG;
|
||||
|
||||
buffer[3U] = 0x00U;
|
||||
if (m_rxInvert)
|
||||
buffer[3U] |= 0x01U;
|
||||
if (m_txInvert)
|
||||
buffer[3U] |= 0x02U;
|
||||
if (m_pttInvert)
|
||||
buffer[3U] |= 0x04U;
|
||||
|
||||
buffer[4U] = 0x00U;
|
||||
if (m_dstarEnabled)
|
||||
buffer[4U] |= 0x01U;
|
||||
if (m_dmrEnabled)
|
||||
buffer[4U] |= 0x02U;
|
||||
if (m_ysfEnabled)
|
||||
buffer[4U] |= 0x04U;
|
||||
|
||||
buffer[5U] = m_txDelay / 10U; // In 10ms units
|
||||
|
||||
buffer[6U] = MODE_IDLE;
|
||||
|
||||
buffer[7U] = (m_rxLevel * 255U) / 100U;
|
||||
buffer[8U] = (m_txLevel * 255U) / 100U;
|
||||
|
||||
buffer[9U] = m_colorCode;
|
||||
|
||||
// CUtils::dump("Written", buffer, 10U);
|
||||
|
||||
int ret = m_serial.write(buffer, 10U);
|
||||
if (ret != 10)
|
||||
return false;
|
||||
|
||||
unsigned int count = 0U;
|
||||
unsigned int length;
|
||||
RESP_TYPE_MMDVM resp;
|
||||
do {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
::Sleep(10UL);
|
||||
#else
|
||||
::usleep(10000UL);
|
||||
#endif
|
||||
resp = getResponse(m_buffer, length);
|
||||
|
||||
if (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK) {
|
||||
count++;
|
||||
if (count >= MAX_RESPONSES) {
|
||||
LogError("The MMDVM is not responding to the SET_CONFIG command");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} while (resp == RTM_OK && m_buffer[2U] != MMDVM_ACK && m_buffer[2U] != MMDVM_NAK);
|
||||
|
||||
// CUtils::dump("Response", m_buffer, length);
|
||||
|
||||
if (resp == RTM_OK && m_buffer[2U] == MMDVM_NAK) {
|
||||
LogError("Received a NAK to the SET_CONFIG command from the modem");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
RESP_TYPE_MMDVM CModem::getResponse(unsigned char *buffer, unsigned int& length)
|
||||
{
|
||||
// Get the start of the frame or nothing at all
|
||||
int ret = m_serial.read(buffer + 0U, 1U);
|
||||
if (ret < 0) {
|
||||
LogError("Error when reading from the modem");
|
||||
return RTM_ERROR;
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
return RTM_TIMEOUT;
|
||||
|
||||
if (buffer[0U] != MMDVM_FRAME_START)
|
||||
return RTM_TIMEOUT;
|
||||
|
||||
ret = m_serial.read(buffer + 1U, 1U);
|
||||
if (ret < 0) {
|
||||
LogError("Error when reading from the modem");
|
||||
return RTM_ERROR;
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
return RTM_TIMEOUT;
|
||||
|
||||
length = buffer[1U];
|
||||
|
||||
if (length >= 200U) {
|
||||
LogError("Invalid data received from the modem");
|
||||
return RTM_ERROR;
|
||||
}
|
||||
|
||||
unsigned int offset = 2U;
|
||||
|
||||
while (offset < length) {
|
||||
int ret = m_serial.read(buffer + offset, length - offset);
|
||||
if (ret < 0) {
|
||||
LogError("Error when reading from the modem");
|
||||
return RTM_ERROR;
|
||||
}
|
||||
|
||||
if (ret > 0)
|
||||
offset += ret;
|
||||
|
||||
if (ret == 0)
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
::Sleep(5UL); // 5ms
|
||||
#else
|
||||
::usleep(5000); // 5ms
|
||||
#endif
|
||||
}
|
||||
|
||||
// CUtils::dump("Received", buffer, length);
|
||||
|
||||
return RTM_OK;
|
||||
}
|
||||
|
||||
bool CModem::setMode(unsigned char mode)
|
||||
{
|
||||
unsigned char buffer[4U];
|
||||
|
||||
buffer[0U] = MMDVM_FRAME_START;
|
||||
buffer[1U] = 4U;
|
||||
buffer[2U] = MMDVM_SET_MODE;
|
||||
buffer[3U] = mode;
|
||||
|
||||
// CUtils::dump("Written", buffer, 4U);
|
||||
|
||||
return m_serial.write(buffer, 4U) == 4;
|
||||
}
|
||||
|
||||
bool CModem::writeDMRStart(bool tx)
|
||||
{
|
||||
if (tx && m_tx)
|
||||
return true;
|
||||
if (!tx && !m_tx)
|
||||
return true;
|
||||
|
||||
unsigned char buffer[4U];
|
||||
|
||||
buffer[0U] = MMDVM_FRAME_START;
|
||||
buffer[1U] = 4U;
|
||||
buffer[2U] = MMDVM_DMR_START;
|
||||
buffer[3U] = tx ? 0x01U : 0x00U;
|
||||
|
||||
// CUtils::dump("Written", buffer, 4U);
|
||||
|
||||
return m_serial.write(buffer, 4U) == 4;
|
||||
}
|
||||
|
||||
bool CModem::writeDMRShortLC(const unsigned char* lc)
|
||||
{
|
||||
assert(lc != NULL);
|
||||
|
||||
unsigned char buffer[12U];
|
||||
|
||||
buffer[0U] = MMDVM_FRAME_START;
|
||||
buffer[1U] = 12U;
|
||||
buffer[2U] = MMDVM_DMR_SHORTLC;
|
||||
buffer[3U] = lc[0U];
|
||||
buffer[4U] = lc[1U];
|
||||
buffer[5U] = lc[2U];
|
||||
buffer[6U] = lc[3U];
|
||||
buffer[7U] = lc[4U];
|
||||
buffer[8U] = lc[5U];
|
||||
buffer[9U] = lc[6U];
|
||||
buffer[10U] = lc[7U];
|
||||
buffer[11U] = lc[8U];
|
||||
|
||||
// CUtils::dump("Written", buffer, 12U);
|
||||
|
||||
return m_serial.write(buffer, 12U) == 12;
|
||||
}
|
||||
|
||||
void CModem::printDebug()
|
||||
{
|
||||
unsigned int length = m_buffer[1U];
|
||||
if (m_buffer[2U] == 0xF1U) {
|
||||
LogMessage("Debug: %.*s", length - 3U, m_buffer + 3U);
|
||||
} else if (m_buffer[2U] == 0xF2U) {
|
||||
short val1 = (m_buffer[length - 2U] << 8) | m_buffer[length - 1U];
|
||||
LogMessage("Debug: %.*s %d", length - 5U, m_buffer + 3U, val1);
|
||||
} else if (m_buffer[2U] == 0xF3U) {
|
||||
short val1 = (m_buffer[length - 4U] << 8) | m_buffer[length - 3U];
|
||||
short val2 = (m_buffer[length - 2U] << 8) | m_buffer[length - 1U];
|
||||
LogMessage("Debug: %.*s %d %d", length - 7U, m_buffer + 3U, val1, val2);
|
||||
} else if (m_buffer[2U] == 0xF4U) {
|
||||
short val1 = (m_buffer[length - 6U] << 8) | m_buffer[length - 5U];
|
||||
short val2 = (m_buffer[length - 4U] << 8) | m_buffer[length - 3U];
|
||||
short val3 = (m_buffer[length - 2U] << 8) | m_buffer[length - 1U];
|
||||
LogMessage("Debug: %.*s %d %d %d", length - 9U, m_buffer + 3U, val1, val2, val3);
|
||||
} else if (m_buffer[2U] == 0xF5U) {
|
||||
short val1 = (m_buffer[length - 8U] << 8) | m_buffer[length - 7U];
|
||||
short val2 = (m_buffer[length - 6U] << 8) | m_buffer[length - 5U];
|
||||
short val3 = (m_buffer[length - 4U] << 8) | m_buffer[length - 3U];
|
||||
short val4 = (m_buffer[length - 2U] << 8) | m_buffer[length - 1U];
|
||||
LogMessage("Debug: %.*s %d %d %d %d", length - 11U, m_buffer + 3U, val1, val2, val3, val4);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef MODEM_H
|
||||
#define MODEM_H
|
||||
|
||||
#include "SerialController.h"
|
||||
#include "RingBuffer.h"
|
||||
#include "Timer.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
enum RESP_TYPE_MMDVM {
|
||||
RTM_OK,
|
||||
RTM_TIMEOUT,
|
||||
RTM_ERROR
|
||||
};
|
||||
|
||||
class CModem {
|
||||
public:
|
||||
CModem(const std::string& port, bool rxInvert, bool txInvert, bool pttInvert, unsigned int txDelay, unsigned int rxLevel, unsigned int txLevel, bool debug = false);
|
||||
virtual ~CModem();
|
||||
|
||||
virtual void setModeParams(bool dstarEnabled, bool dmrEnabled, bool ysfEnabled);
|
||||
virtual void setDMRParams(unsigned int colorCode);
|
||||
|
||||
virtual bool open();
|
||||
|
||||
virtual unsigned int readDStarData(unsigned char* data);
|
||||
virtual unsigned int readDMRData1(unsigned char* data);
|
||||
virtual unsigned int readDMRData2(unsigned char* data);
|
||||
virtual unsigned int readYSFData(unsigned char* data);
|
||||
|
||||
virtual bool hasDStarSpace() const;
|
||||
virtual bool hasDMRSpace1() const;
|
||||
virtual bool hasDMRSpace2() const;
|
||||
virtual bool hasYSFSpace() const;
|
||||
|
||||
virtual bool writeDStarData(const unsigned char* data, unsigned int length);
|
||||
virtual bool writeDMRData1(const unsigned char* data, unsigned int length);
|
||||
virtual bool writeDMRData2(const unsigned char* data, unsigned int length);
|
||||
virtual bool writeYSFData(const unsigned char* data, unsigned int length);
|
||||
|
||||
virtual bool writeDMRStart(bool tx);
|
||||
virtual bool writeDMRShortLC(const unsigned char* lc);
|
||||
|
||||
virtual bool setMode(unsigned char mode);
|
||||
|
||||
virtual void clock(unsigned int ms);
|
||||
|
||||
virtual void close();
|
||||
|
||||
private:
|
||||
std::string m_port;
|
||||
unsigned int m_colorCode;
|
||||
bool m_rxInvert;
|
||||
bool m_txInvert;
|
||||
bool m_pttInvert;
|
||||
unsigned int m_txDelay;
|
||||
unsigned int m_rxLevel;
|
||||
unsigned int m_txLevel;
|
||||
bool m_debug;
|
||||
bool m_dstarEnabled;
|
||||
bool m_dmrEnabled;
|
||||
bool m_ysfEnabled;
|
||||
CSerialController m_serial;
|
||||
unsigned char* m_buffer;
|
||||
CRingBuffer<unsigned char> m_rxDStarData;
|
||||
CRingBuffer<unsigned char> m_txDStarData;
|
||||
CRingBuffer<unsigned char> m_rxDMRData1;
|
||||
CRingBuffer<unsigned char> m_rxDMRData2;
|
||||
CRingBuffer<unsigned char> m_txDMRData1;
|
||||
CRingBuffer<unsigned char> m_txDMRData2;
|
||||
CRingBuffer<unsigned char> m_rxYSFData;
|
||||
CRingBuffer<unsigned char> m_txYSFData;
|
||||
CTimer m_statusTimer;
|
||||
unsigned int m_dstarSpace;
|
||||
unsigned int m_dmrSpace1;
|
||||
unsigned int m_dmrSpace2;
|
||||
unsigned int m_ysfSpace;
|
||||
bool m_tx;
|
||||
|
||||
bool readVersion();
|
||||
bool readStatus();
|
||||
bool setConfig();
|
||||
|
||||
void printDebug();
|
||||
|
||||
RESP_TYPE_MMDVM getResponse(unsigned char* buffer, unsigned int& length);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (C) 2016 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "NullDisplay.h"
|
||||
|
||||
CNullDisplay::CNullDisplay()
|
||||
{
|
||||
}
|
||||
|
||||
CNullDisplay::~CNullDisplay()
|
||||
{
|
||||
}
|
||||
|
||||
bool CNullDisplay::open()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void CNullDisplay::setIdle()
|
||||
{
|
||||
}
|
||||
|
||||
void CNullDisplay::setDStar()
|
||||
{
|
||||
}
|
||||
|
||||
void CNullDisplay::writeDStar(const std::string& call1, const std::string& call2)
|
||||
{
|
||||
}
|
||||
|
||||
void CNullDisplay::clearDStar()
|
||||
{
|
||||
}
|
||||
|
||||
void CNullDisplay::setDMR()
|
||||
{
|
||||
}
|
||||
|
||||
void CNullDisplay::writeDMR(unsigned int slotNo, unsigned int srcId, bool group, unsigned int dstId)
|
||||
{
|
||||
}
|
||||
|
||||
void CNullDisplay::clearDMR(unsigned int slotNo)
|
||||
{
|
||||
}
|
||||
|
||||
void CNullDisplay::setFusion()
|
||||
{
|
||||
}
|
||||
|
||||
void CNullDisplay::writeFusion(const std::string& callsign)
|
||||
{
|
||||
}
|
||||
|
||||
void CNullDisplay::clearFusion()
|
||||
{
|
||||
}
|
||||
|
||||
void CNullDisplay::close()
|
||||
{
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright (C) 2016 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#if !defined(NULLDISPLAY_H)
|
||||
#define NULLDISPLAY_H
|
||||
|
||||
#include "Display.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class CNullDisplay : public IDisplay
|
||||
{
|
||||
public:
|
||||
CNullDisplay();
|
||||
virtual ~CNullDisplay();
|
||||
|
||||
virtual bool open();
|
||||
|
||||
virtual void setIdle();
|
||||
|
||||
virtual void setDStar();
|
||||
virtual void writeDStar(const std::string& call1, const std::string& call2);
|
||||
virtual void clearDStar();
|
||||
|
||||
virtual void setDMR();
|
||||
virtual void writeDMR(unsigned int slotNo, unsigned int srdId, bool group, unsigned int dstId);
|
||||
virtual void clearDMR(unsigned int slotNo);
|
||||
|
||||
virtual void setFusion();
|
||||
virtual void writeFusion(const std::string& callsign);
|
||||
virtual void clearFusion();
|
||||
|
||||
virtual void close();
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#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,6 @@
|
|||
These are the source files for builing the MMDVMHost, the program that
|
||||
interfaces to the MMDVM on one side, and a network on the other.
|
||||
|
||||
It supports D-Star, DMR, and System Fusion.
|
||||
|
||||
It builds on Linux as well as Windows using VS2015 on x86 and x64.
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* Copyright (C) 2015 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "RS129.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
const unsigned int NPAR = 3U;
|
||||
|
||||
/* Maximum degree of various polynomials. */
|
||||
const unsigned int MAXDEG = NPAR * 2U;
|
||||
|
||||
/* Generator Polynomial */
|
||||
const unsigned char POLY[] = {64U, 56U, 14U, 1U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U};
|
||||
|
||||
const unsigned char EXP_TABLE[] = {
|
||||
0x01U, 0x02U, 0x04U, 0x08U, 0x10U, 0x20U, 0x40U, 0x80U, 0x1DU, 0x3AU, 0x74U, 0xE8U, 0xCDU, 0x87U, 0x13U, 0x26U,
|
||||
0x4CU, 0x98U, 0x2DU, 0x5AU, 0xB4U, 0x75U, 0xEAU, 0xC9U, 0x8FU, 0x03U, 0x06U, 0x0CU, 0x18U, 0x30U, 0x60U, 0xC0U,
|
||||
0x9DU, 0x27U, 0x4EU, 0x9CU, 0x25U, 0x4AU, 0x94U, 0x35U, 0x6AU, 0xD4U, 0xB5U, 0x77U, 0xEEU, 0xC1U, 0x9FU, 0x23U,
|
||||
0x46U, 0x8CU, 0x05U, 0x0AU, 0x14U, 0x28U, 0x50U, 0xA0U, 0x5DU, 0xBAU, 0x69U, 0xD2U, 0xB9U, 0x6FU, 0xDEU, 0xA1U,
|
||||
0x5FU, 0xBEU, 0x61U, 0xC2U, 0x99U, 0x2FU, 0x5EU, 0xBCU, 0x65U, 0xCAU, 0x89U, 0x0FU, 0x1EU, 0x3CU, 0x78U, 0xF0U,
|
||||
0xFDU, 0xE7U, 0xD3U, 0xBBU, 0x6BU, 0xD6U, 0xB1U, 0x7FU, 0xFEU, 0xE1U, 0xDFU, 0xA3U, 0x5BU, 0xB6U, 0x71U, 0xE2U,
|
||||
0xD9U, 0xAFU, 0x43U, 0x86U, 0x11U, 0x22U, 0x44U, 0x88U, 0x0DU, 0x1AU, 0x34U, 0x68U, 0xD0U, 0xBDU, 0x67U, 0xCEU,
|
||||
0x81U, 0x1FU, 0x3EU, 0x7CU, 0xF8U, 0xEDU, 0xC7U, 0x93U, 0x3BU, 0x76U, 0xECU, 0xC5U, 0x97U, 0x33U, 0x66U, 0xCCU,
|
||||
0x85U, 0x17U, 0x2EU, 0x5CU, 0xB8U, 0x6DU, 0xDAU, 0xA9U, 0x4FU, 0x9EU, 0x21U, 0x42U, 0x84U, 0x15U, 0x2AU, 0x54U,
|
||||
0xA8U, 0x4DU, 0x9AU, 0x29U, 0x52U, 0xA4U, 0x55U, 0xAAU, 0x49U, 0x92U, 0x39U, 0x72U, 0xE4U, 0xD5U, 0xB7U, 0x73U,
|
||||
0xE6U, 0xD1U, 0xBFU, 0x63U, 0xC6U, 0x91U, 0x3FU, 0x7EU, 0xFCU, 0xE5U, 0xD7U, 0xB3U, 0x7BU, 0xF6U, 0xF1U, 0xFFU,
|
||||
0xE3U, 0xDBU, 0xABU, 0x4BU, 0x96U, 0x31U, 0x62U, 0xC4U, 0x95U, 0x37U, 0x6EU, 0xDCU, 0xA5U, 0x57U, 0xAEU, 0x41U,
|
||||
0x82U, 0x19U, 0x32U, 0x64U, 0xC8U, 0x8DU, 0x07U, 0x0EU, 0x1CU, 0x38U, 0x70U, 0xE0U, 0xDDU, 0xA7U, 0x53U, 0xA6U,
|
||||
0x51U, 0xA2U, 0x59U, 0xB2U, 0x79U, 0xF2U, 0xF9U, 0xEFU, 0xC3U, 0x9BU, 0x2BU, 0x56U, 0xACU, 0x45U, 0x8AU, 0x09U,
|
||||
0x12U, 0x24U, 0x48U, 0x90U, 0x3DU, 0x7AU, 0xF4U, 0xF5U, 0xF7U, 0xF3U, 0xFBU, 0xEBU, 0xCBU, 0x8BU, 0x0BU, 0x16U,
|
||||
0x2CU, 0x58U, 0xB0U, 0x7DU, 0xFAU, 0xE9U, 0xCFU, 0x83U, 0x1BU, 0x36U, 0x6CU, 0xD8U, 0xADU, 0x47U, 0x8EU, 0x01U,
|
||||
0x02U, 0x04U, 0x08U, 0x10U, 0x20U, 0x40U, 0x80U, 0x1DU, 0x3AU, 0x74U, 0xE8U, 0xCDU, 0x87U, 0x13U, 0x26U, 0x4CU,
|
||||
0x98U, 0x2DU, 0x5AU, 0xB4U, 0x75U, 0xEAU, 0xC9U, 0x8FU, 0x03U, 0x06U, 0x0CU, 0x18U, 0x30U, 0x60U, 0xC0U, 0x9DU,
|
||||
0x27U, 0x4EU, 0x9CU, 0x25U, 0x4AU, 0x94U, 0x35U, 0x6AU, 0xD4U, 0xB5U, 0x77U, 0xEEU, 0xC1U, 0x9FU, 0x23U, 0x46U,
|
||||
0x8CU, 0x05U, 0x0AU, 0x14U, 0x28U, 0x50U, 0xA0U, 0x5DU, 0xBAU, 0x69U, 0xD2U, 0xB9U, 0x6FU, 0xDEU, 0xA1U, 0x5FU,
|
||||
0xBEU, 0x61U, 0xC2U, 0x99U, 0x2FU, 0x5EU, 0xBCU, 0x65U, 0xCAU, 0x89U, 0x0FU, 0x1EU, 0x3CU, 0x78U, 0xF0U, 0xFDU,
|
||||
0xE7U, 0xD3U, 0xBBU, 0x6BU, 0xD6U, 0xB1U, 0x7FU, 0xFEU, 0xE1U, 0xDFU, 0xA3U, 0x5BU, 0xB6U, 0x71U, 0xE2U, 0xD9U,
|
||||
0xAFU, 0x43U, 0x86U, 0x11U, 0x22U, 0x44U, 0x88U, 0x0DU, 0x1AU, 0x34U, 0x68U, 0xD0U, 0xBDU, 0x67U, 0xCEU, 0x81U,
|
||||
0x1FU, 0x3EU, 0x7CU, 0xF8U, 0xEDU, 0xC7U, 0x93U, 0x3BU, 0x76U, 0xECU, 0xC5U, 0x97U, 0x33U, 0x66U, 0xCCU, 0x85U,
|
||||
0x17U, 0x2EU, 0x5CU, 0xB8U, 0x6DU, 0xDAU, 0xA9U, 0x4FU, 0x9EU, 0x21U, 0x42U, 0x84U, 0x15U, 0x2AU, 0x54U, 0xA8U,
|
||||
0x4DU, 0x9AU, 0x29U, 0x52U, 0xA4U, 0x55U, 0xAAU, 0x49U, 0x92U, 0x39U, 0x72U, 0xE4U, 0xD5U, 0xB7U, 0x73U, 0xE6U,
|
||||
0xD1U, 0xBFU, 0x63U, 0xC6U, 0x91U, 0x3FU, 0x7EU, 0xFCU, 0xE5U, 0xD7U, 0xB3U, 0x7BU, 0xF6U, 0xF1U, 0xFFU, 0xE3U,
|
||||
0xDBU, 0xABU, 0x4BU, 0x96U, 0x31U, 0x62U, 0xC4U, 0x95U, 0x37U, 0x6EU, 0xDCU, 0xA5U, 0x57U, 0xAEU, 0x41U, 0x82U,
|
||||
0x19U, 0x32U, 0x64U, 0xC8U, 0x8DU, 0x07U, 0x0EU, 0x1CU, 0x38U, 0x70U, 0xE0U, 0xDDU, 0xA7U, 0x53U, 0xA6U, 0x51U,
|
||||
0xA2U, 0x59U, 0xB2U, 0x79U, 0xF2U, 0xF9U, 0xEFU, 0xC3U, 0x9BU, 0x2BU, 0x56U, 0xACU, 0x45U, 0x8AU, 0x09U, 0x12U,
|
||||
0x24U, 0x48U, 0x90U, 0x3DU, 0x7AU, 0xF4U, 0xF5U, 0xF7U, 0xF3U, 0xFBU, 0xEBU, 0xCBU, 0x8BU, 0x0BU, 0x16U, 0x2CU,
|
||||
0x58U, 0xB0U, 0x7DU, 0xFAU, 0xE9U, 0xCFU, 0x83U, 0x1BU, 0x36U, 0x6CU, 0xD8U, 0xADU, 0x47U, 0x8EU, 0x01U, 0x00U};
|
||||
|
||||
const unsigned char LOG_TABLE[] = {
|
||||
0x00U, 0x00U, 0x01U, 0x19U, 0x02U, 0x32U, 0x1AU, 0xC6U, 0x03U, 0xDFU, 0x33U, 0xEEU, 0x1BU, 0x68U, 0xC7U, 0x4BU,
|
||||
0x04U, 0x64U, 0xE0U, 0x0EU, 0x34U, 0x8DU, 0xEFU, 0x81U, 0x1CU, 0xC1U, 0x69U, 0xF8U, 0xC8U, 0x08U, 0x4CU, 0x71U,
|
||||
0x05U, 0x8AU, 0x65U, 0x2FU, 0xE1U, 0x24U, 0x0FU, 0x21U, 0x35U, 0x93U, 0x8EU, 0xDAU, 0xF0U, 0x12U, 0x82U, 0x45U,
|
||||
0x1DU, 0xB5U, 0xC2U, 0x7DU, 0x6AU, 0x27U, 0xF9U, 0xB9U, 0xC9U, 0x9AU, 0x09U, 0x78U, 0x4DU, 0xE4U, 0x72U, 0xA6U,
|
||||
0x06U, 0xBFU, 0x8BU, 0x62U, 0x66U, 0xDDU, 0x30U, 0xFDU, 0xE2U, 0x98U, 0x25U, 0xB3U, 0x10U, 0x91U, 0x22U, 0x88U,
|
||||
0x36U, 0xD0U, 0x94U, 0xCEU, 0x8FU, 0x96U, 0xDBU, 0xBDU, 0xF1U, 0xD2U, 0x13U, 0x5CU, 0x83U, 0x38U, 0x46U, 0x40U,
|
||||
0x1EU, 0x42U, 0xB6U, 0xA3U, 0xC3U, 0x48U, 0x7EU, 0x6EU, 0x6BU, 0x3AU, 0x28U, 0x54U, 0xFAU, 0x85U, 0xBAU, 0x3DU,
|
||||
0xCAU, 0x5EU, 0x9BU, 0x9FU, 0x0AU, 0x15U, 0x79U, 0x2BU, 0x4EU, 0xD4U, 0xE5U, 0xACU, 0x73U, 0xF3U, 0xA7U, 0x57U,
|
||||
0x07U, 0x70U, 0xC0U, 0xF7U, 0x8CU, 0x80U, 0x63U, 0x0DU, 0x67U, 0x4AU, 0xDEU, 0xEDU, 0x31U, 0xC5U, 0xFEU, 0x18U,
|
||||
0xE3U, 0xA5U, 0x99U, 0x77U, 0x26U, 0xB8U, 0xB4U, 0x7CU, 0x11U, 0x44U, 0x92U, 0xD9U, 0x23U, 0x20U, 0x89U, 0x2EU,
|
||||
0x37U, 0x3FU, 0xD1U, 0x5BU, 0x95U, 0xBCU, 0xCFU, 0xCDU, 0x90U, 0x87U, 0x97U, 0xB2U, 0xDCU, 0xFCU, 0xBEU, 0x61U,
|
||||
0xF2U, 0x56U, 0xD3U, 0xABU, 0x14U, 0x2AU, 0x5DU, 0x9EU, 0x84U, 0x3CU, 0x39U, 0x53U, 0x47U, 0x6DU, 0x41U, 0xA2U,
|
||||
0x1FU, 0x2DU, 0x43U, 0xD8U, 0xB7U, 0x7BU, 0xA4U, 0x76U, 0xC4U, 0x17U, 0x49U, 0xECU, 0x7FU, 0x0CU, 0x6FU, 0xF6U,
|
||||
0x6CU, 0xA1U, 0x3BU, 0x52U, 0x29U, 0x9DU, 0x55U, 0xAAU, 0xFBU, 0x60U, 0x86U, 0xB1U, 0xBBU, 0xCCU, 0x3EU, 0x5AU,
|
||||
0xCBU, 0x59U, 0x5FU, 0xB0U, 0x9CU, 0xA9U, 0xA0U, 0x51U, 0x0BU, 0xF5U, 0x16U, 0xEBU, 0x7AU, 0x75U, 0x2CU, 0xD7U,
|
||||
0x4FU, 0xAEU, 0xD5U, 0xE9U, 0xE6U, 0xE7U, 0xADU, 0xE8U, 0x74U, 0xD6U, 0xF4U, 0xEAU, 0xA8U, 0x50U, 0x58U, 0xAFU};
|
||||
|
||||
/* multiplication using logarithms */
|
||||
static unsigned char gmult(unsigned char a, unsigned char b)
|
||||
{
|
||||
if (a == 0U || b == 0U)
|
||||
return 0U;
|
||||
|
||||
unsigned int i = LOG_TABLE[a];
|
||||
unsigned int j = LOG_TABLE[b];
|
||||
|
||||
return EXP_TABLE[i + j];
|
||||
}
|
||||
|
||||
/* Simulate a LFSR with generator polynomial for n byte RS code.
|
||||
* Pass in a pointer to the data array, and amount of data.
|
||||
*
|
||||
* The parity bytes are deposited into parity.
|
||||
*/
|
||||
void CRS129::encode(const unsigned char* msg, unsigned int nbytes, unsigned char* parity)
|
||||
{
|
||||
assert(msg != NULL);
|
||||
assert(parity != NULL);
|
||||
|
||||
for (unsigned int i = 0U; i < NPAR + 1U; i++)
|
||||
parity[i] = 0x00U;
|
||||
|
||||
for (unsigned int i = 0U; i < nbytes; i++) {
|
||||
unsigned char dbyte = msg[i] ^ parity[NPAR - 1U];
|
||||
|
||||
for (int j = NPAR - 1; j > 0; j--)
|
||||
parity[j] = parity[j - 1] ^ ::gmult(POLY[j], dbyte);
|
||||
|
||||
parity[0] = ::gmult(POLY[0], dbyte);
|
||||
}
|
||||
}
|
||||
|
||||
// Reed-Solomon (12,9) check
|
||||
bool CRS129::check(const unsigned char* in)
|
||||
{
|
||||
assert(in != NULL);
|
||||
|
||||
unsigned char parity[4U];
|
||||
encode(in, 9U, parity);
|
||||
|
||||
return in[9U] == parity[2U] && in[10U] == parity[1U] && in[11U] == parity[0U];
|
||||
}
|
||||
|
|
@ -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,144 @@
|
|||
/*
|
||||
* Copyright (C) 2006-2009,2012,2013,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 RingBuffer_H
|
||||
#define RingBuffer_H
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
template<class T> class CRingBuffer {
|
||||
public:
|
||||
CRingBuffer(unsigned int length) :
|
||||
m_length(length),
|
||||
m_buffer(NULL),
|
||||
m_iPtr(0U),
|
||||
m_oPtr(0U)
|
||||
{
|
||||
assert(length > 0U);
|
||||
|
||||
m_buffer = new T[length];
|
||||
|
||||
::memset(m_buffer, 0x00, m_length * sizeof(T));
|
||||
}
|
||||
|
||||
~CRingBuffer()
|
||||
{
|
||||
delete[] m_buffer;
|
||||
}
|
||||
|
||||
unsigned int addData(const T* buffer, unsigned int nSamples)
|
||||
{
|
||||
if (nSamples > freeSpace())
|
||||
return 0U;
|
||||
|
||||
for (unsigned int i = 0U; i < nSamples; i++) {
|
||||
m_buffer[m_iPtr++] = buffer[i];
|
||||
|
||||
if (m_iPtr == m_length)
|
||||
m_iPtr = 0U;
|
||||
}
|
||||
|
||||
return nSamples;
|
||||
}
|
||||
|
||||
unsigned int getData(T* buffer, unsigned int nSamples)
|
||||
{
|
||||
unsigned int data = dataSize();
|
||||
|
||||
if (data < nSamples)
|
||||
nSamples = data;
|
||||
|
||||
for (unsigned int i = 0U; i < nSamples; i++) {
|
||||
buffer[i] = m_buffer[m_oPtr++];
|
||||
|
||||
if (m_oPtr == m_length)
|
||||
m_oPtr = 0U;
|
||||
}
|
||||
|
||||
return nSamples;
|
||||
}
|
||||
|
||||
unsigned int peek(T* buffer, unsigned int nSamples)
|
||||
{
|
||||
unsigned int data = dataSize();
|
||||
|
||||
if (data < nSamples)
|
||||
nSamples = data;
|
||||
|
||||
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 nSamples;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_iPtr = 0U;
|
||||
m_oPtr = 0U;
|
||||
|
||||
::memset(m_buffer, 0x00, m_length * sizeof(T));
|
||||
}
|
||||
|
||||
unsigned int freeSpace() const
|
||||
{
|
||||
if (m_oPtr == m_iPtr)
|
||||
return m_length - 1U;
|
||||
|
||||
if (m_oPtr > m_iPtr)
|
||||
return m_oPtr - m_iPtr - 1U;
|
||||
|
||||
return m_length - (m_iPtr - m_oPtr) - 1U;
|
||||
}
|
||||
|
||||
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;
|
||||
T* m_buffer;
|
||||
volatile unsigned int m_iPtr;
|
||||
volatile unsigned int m_oPtr;
|
||||
|
||||
unsigned int dataSize() const
|
||||
{
|
||||
if (m_iPtr >= m_oPtr)
|
||||
return m_iPtr - m_oPtr;
|
||||
|
||||
return m_length - (m_oPtr - m_iPtr);
|
||||
}
|
||||
};
|
||||
|
||||
#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,77 @@
|
|||
/*
|
||||
* Copyright (C) 2005, 2006, 2008, 2009 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.
|
||||
*/
|
||||
|
||||
#ifndef SHA256_H
|
||||
#define SHA256_H
|
||||
|
||||
#if defined(WIN32)
|
||||
typedef unsigned int uint32_t;
|
||||
#else
|
||||
#include <cstdint>
|
||||
#endif
|
||||
|
||||
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,467 @@
|
|||
/*
|
||||
* Copyright (C) 2002-2004,2007-2011,2013,2014,2015 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 1999-2001 by Thomas Sailor HB9JNX
|
||||
*
|
||||
* 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 "SerialController.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#if defined(WIN32)
|
||||
#include <setupapi.h>
|
||||
#include <winioctl.h>
|
||||
#else
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <cerrno>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(WIN32)
|
||||
|
||||
const unsigned int BUFFER_LENGTH = 1000U;
|
||||
|
||||
CSerialController::CSerialController(const std::string& device, SERIAL_SPEED speed, bool assertRTS) :
|
||||
m_device(device),
|
||||
m_speed(speed),
|
||||
m_assertRTS(assertRTS),
|
||||
m_handle(INVALID_HANDLE_VALUE),
|
||||
m_readOverlapped(),
|
||||
m_writeOverlapped(),
|
||||
m_readBuffer(NULL),
|
||||
m_readLength(0U),
|
||||
m_readPending(false)
|
||||
{
|
||||
assert(!device.empty());
|
||||
|
||||
m_readBuffer = new unsigned char[BUFFER_LENGTH];
|
||||
}
|
||||
|
||||
CSerialController::~CSerialController()
|
||||
{
|
||||
delete[] m_readBuffer;
|
||||
}
|
||||
|
||||
bool CSerialController::open()
|
||||
{
|
||||
assert(m_handle == INVALID_HANDLE_VALUE);
|
||||
|
||||
DWORD errCode;
|
||||
|
||||
std::string baseName = m_device.substr(4U); // Convert "\\.\COM10" to "COM10"
|
||||
|
||||
m_handle = ::CreateFileA(m_device.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
|
||||
if (m_handle == INVALID_HANDLE_VALUE) {
|
||||
LogError("Cannot open device - %s, err=%04lx", m_device.c_str(), ::GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
DCB dcb;
|
||||
if (::GetCommState(m_handle, &dcb) == 0) {
|
||||
LogError("Cannot get the attributes for %s, err=%04lx", m_device.c_str(), ::GetLastError());
|
||||
::ClearCommError(m_handle, &errCode, NULL);
|
||||
::CloseHandle(m_handle);
|
||||
return false;
|
||||
}
|
||||
|
||||
dcb.BaudRate = DWORD(m_speed);
|
||||
dcb.ByteSize = 8;
|
||||
dcb.Parity = NOPARITY;
|
||||
dcb.fParity = FALSE;
|
||||
dcb.StopBits = ONESTOPBIT;
|
||||
dcb.fInX = FALSE;
|
||||
dcb.fOutX = FALSE;
|
||||
dcb.fOutxCtsFlow = FALSE;
|
||||
dcb.fOutxDsrFlow = FALSE;
|
||||
dcb.fDtrControl = DTR_CONTROL_DISABLE;
|
||||
dcb.fRtsControl = RTS_CONTROL_DISABLE;
|
||||
|
||||
if (::SetCommState(m_handle, &dcb) == 0) {
|
||||
LogError("Cannot set the attributes for %s, err=%04lx", m_device.c_str(), ::GetLastError());
|
||||
::ClearCommError(m_handle, &errCode, NULL);
|
||||
::CloseHandle(m_handle);
|
||||
return false;
|
||||
}
|
||||
|
||||
COMMTIMEOUTS timeouts;
|
||||
if (!::GetCommTimeouts(m_handle, &timeouts)) {
|
||||
LogError("Cannot get the timeouts for %s, err=%04lx", m_device.c_str(), ::GetLastError());
|
||||
::ClearCommError(m_handle, &errCode, NULL);
|
||||
::CloseHandle(m_handle);
|
||||
return false;
|
||||
}
|
||||
|
||||
timeouts.ReadIntervalTimeout = MAXDWORD;
|
||||
timeouts.ReadTotalTimeoutMultiplier = 0UL;
|
||||
timeouts.ReadTotalTimeoutConstant = 0UL;
|
||||
|
||||
if (!::SetCommTimeouts(m_handle, &timeouts)) {
|
||||
LogError("Cannot set the timeouts for %s, err=%04lx", m_device.c_str(), ::GetLastError());
|
||||
::ClearCommError(m_handle, &errCode, NULL);
|
||||
::CloseHandle(m_handle);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (::EscapeCommFunction(m_handle, CLRDTR) == 0) {
|
||||
LogError("Cannot clear DTR for %s, err=%04lx", m_device.c_str(), ::GetLastError());
|
||||
::ClearCommError(m_handle, &errCode, NULL);
|
||||
::CloseHandle(m_handle);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (::EscapeCommFunction(m_handle, m_assertRTS ? SETRTS : CLRRTS) == 0) {
|
||||
LogError("Cannot set/clear RTS for %s, err=%04lx", m_device.c_str(), ::GetLastError());
|
||||
::ClearCommError(m_handle, &errCode, NULL);
|
||||
::CloseHandle(m_handle);
|
||||
return false;
|
||||
}
|
||||
|
||||
::ClearCommError(m_handle, &errCode, NULL);
|
||||
|
||||
::memset(&m_readOverlapped, 0x00U, sizeof(OVERLAPPED));
|
||||
::memset(&m_writeOverlapped, 0x00U, sizeof(OVERLAPPED));
|
||||
|
||||
m_readOverlapped.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
m_writeOverlapped.hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
m_readLength = 0U;
|
||||
m_readPending = false;
|
||||
::memset(m_readBuffer, 0x00U, BUFFER_LENGTH);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int CSerialController::read(unsigned char* buffer, unsigned int length)
|
||||
{
|
||||
assert(m_handle != INVALID_HANDLE_VALUE);
|
||||
assert(buffer != NULL);
|
||||
|
||||
unsigned int ptr = 0U;
|
||||
|
||||
while (ptr < length) {
|
||||
int ret = readNonblock(buffer + ptr, length - ptr);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
} else if (ret == 0) {
|
||||
if (ptr == 0U)
|
||||
return 0;
|
||||
} else {
|
||||
ptr += ret;
|
||||
}
|
||||
}
|
||||
|
||||
return int(length);
|
||||
}
|
||||
|
||||
int CSerialController::readNonblock(unsigned char* buffer, unsigned int length)
|
||||
{
|
||||
assert(m_handle != INVALID_HANDLE_VALUE);
|
||||
assert(buffer != NULL);
|
||||
|
||||
if (length > BUFFER_LENGTH)
|
||||
length = BUFFER_LENGTH;
|
||||
|
||||
if (m_readPending && length != m_readLength) {
|
||||
::CancelIo(m_handle);
|
||||
m_readPending = false;
|
||||
}
|
||||
|
||||
m_readLength = length;
|
||||
|
||||
if (length == 0U)
|
||||
return 0;
|
||||
|
||||
if (!m_readPending) {
|
||||
DWORD bytes = 0UL;
|
||||
BOOL res = ::ReadFile(m_handle, m_readBuffer, m_readLength, &bytes, &m_readOverlapped);
|
||||
if (res) {
|
||||
::memcpy(buffer, m_readBuffer, bytes);
|
||||
return int(bytes);
|
||||
}
|
||||
|
||||
DWORD error = ::GetLastError();
|
||||
if (error != ERROR_IO_PENDING) {
|
||||
LogError("Error from ReadFile: %04lx", error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
m_readPending = true;
|
||||
}
|
||||
|
||||
BOOL res = HasOverlappedIoCompleted(&m_readOverlapped);
|
||||
if (!res)
|
||||
return 0;
|
||||
|
||||
DWORD bytes = 0UL;
|
||||
res = ::GetOverlappedResult(m_handle, &m_readOverlapped, &bytes, TRUE);
|
||||
if (!res) {
|
||||
LogError("Error from GetOverlappedResult (ReadFile): %04lx", ::GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
::memcpy(buffer, m_readBuffer, bytes);
|
||||
m_readPending = false;
|
||||
|
||||
return int(bytes);
|
||||
}
|
||||
|
||||
int CSerialController::write(const unsigned char* buffer, unsigned int length)
|
||||
{
|
||||
assert(m_handle != INVALID_HANDLE_VALUE);
|
||||
assert(buffer != NULL);
|
||||
|
||||
if (length == 0U)
|
||||
return 0;
|
||||
|
||||
unsigned int ptr = 0U;
|
||||
|
||||
while (ptr < length) {
|
||||
DWORD bytes = 0UL;
|
||||
BOOL res = ::WriteFile(m_handle, buffer + ptr, length - ptr, &bytes, &m_writeOverlapped);
|
||||
if (!res) {
|
||||
DWORD error = ::GetLastError();
|
||||
if (error != ERROR_IO_PENDING) {
|
||||
LogError("Error from WriteFile: %04lx", error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = ::GetOverlappedResult(m_handle, &m_writeOverlapped, &bytes, TRUE);
|
||||
if (!res) {
|
||||
LogError("Error from GetOverlappedResult (WriteFile): %04lx", ::GetLastError());
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
ptr += bytes;
|
||||
}
|
||||
|
||||
return int(length);
|
||||
}
|
||||
|
||||
void CSerialController::close()
|
||||
{
|
||||
assert(m_handle != INVALID_HANDLE_VALUE);
|
||||
|
||||
::CloseHandle(m_handle);
|
||||
m_handle = INVALID_HANDLE_VALUE;
|
||||
|
||||
::CloseHandle(m_readOverlapped.hEvent);
|
||||
::CloseHandle(m_writeOverlapped.hEvent);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
CSerialController::CSerialController(const std::string& device, SERIAL_SPEED speed, bool assertRTS) :
|
||||
m_device(device),
|
||||
m_speed(speed),
|
||||
m_assertRTS(assertRTS),
|
||||
m_fd(-1)
|
||||
{
|
||||
assert(!device.empty());
|
||||
}
|
||||
|
||||
CSerialController::~CSerialController()
|
||||
{
|
||||
}
|
||||
|
||||
bool CSerialController::open()
|
||||
{
|
||||
assert(m_fd == -1);
|
||||
|
||||
m_fd = ::open(m_device.c_str(), O_RDWR | O_NOCTTY | O_NDELAY, 0);
|
||||
if (m_fd < 0) {
|
||||
LogError("Cannot open device - %s", m_device.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (::isatty(m_fd) == 0) {
|
||||
LogError("%s is not a TTY device", m_device.c_str());
|
||||
::close(m_fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
termios termios;
|
||||
if (::tcgetattr(m_fd, &termios) < 0) {
|
||||
LogError("Cannot get the attributes for %s", m_device.c_str());
|
||||
::close(m_fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
termios.c_lflag &= ~(ECHO | ECHOE | ICANON | IEXTEN | ISIG);
|
||||
termios.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON | IXOFF | IXANY);
|
||||
termios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CRTSCTS);
|
||||
termios.c_cflag |= CS8;
|
||||
termios.c_oflag &= ~(OPOST);
|
||||
termios.c_cc[VMIN] = 0;
|
||||
termios.c_cc[VTIME] = 10;
|
||||
|
||||
switch (m_speed) {
|
||||
case SERIAL_1200:
|
||||
::cfsetospeed(&termios, B1200);
|
||||
::cfsetispeed(&termios, B1200);
|
||||
break;
|
||||
case SERIAL_2400:
|
||||
::cfsetospeed(&termios, B2400);
|
||||
::cfsetispeed(&termios, B2400);
|
||||
break;
|
||||
case SERIAL_4800:
|
||||
::cfsetospeed(&termios, B4800);
|
||||
::cfsetispeed(&termios, B4800);
|
||||
break;
|
||||
case SERIAL_9600:
|
||||
::cfsetospeed(&termios, B9600);
|
||||
::cfsetispeed(&termios, B9600);
|
||||
break;
|
||||
case SERIAL_19200:
|
||||
::cfsetospeed(&termios, B19200);
|
||||
::cfsetispeed(&termios, B19200);
|
||||
break;
|
||||
case SERIAL_38400:
|
||||
::cfsetospeed(&termios, B38400);
|
||||
::cfsetispeed(&termios, B38400);
|
||||
break;
|
||||
case SERIAL_115200:
|
||||
::cfsetospeed(&termios, B115200);
|
||||
::cfsetispeed(&termios, B115200);
|
||||
break;
|
||||
case SERIAL_230400:
|
||||
::cfsetospeed(&termios, B230400);
|
||||
::cfsetispeed(&termios, B230400);
|
||||
break;
|
||||
default:
|
||||
LogError("Unsupported serial port speed - %d", int(m_speed));
|
||||
::close(m_fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (::tcsetattr(m_fd, TCSANOW, &termios) < 0) {
|
||||
LogError("Cannot set the attributes for %s", m_device.c_str());
|
||||
::close(m_fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_assertRTS) {
|
||||
unsigned int y;
|
||||
if (::ioctl(m_fd, TIOCMGET, &y) < 0) {
|
||||
LogError("Cannot get the control attributes for %s", m_device.c_str());
|
||||
::close(m_fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
y |= TIOCM_RTS;
|
||||
|
||||
if (::ioctl(m_fd, TIOCMSET, &y) < 0) {
|
||||
LogError("Cannot set the control attributes for %s", m_device.c_str());
|
||||
::close(m_fd);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int CSerialController::read(unsigned char* buffer, unsigned int length)
|
||||
{
|
||||
assert(buffer != NULL);
|
||||
assert(m_fd != -1);
|
||||
|
||||
if (length == 0U)
|
||||
return 0;
|
||||
|
||||
unsigned int offset = 0U;
|
||||
|
||||
while (offset < length) {
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(m_fd, &fds);
|
||||
|
||||
int n;
|
||||
if (offset == 0U) {
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
n = ::select(m_fd + 1, &fds, NULL, NULL, &tv);
|
||||
if (n == 0)
|
||||
return 0;
|
||||
} else {
|
||||
n = ::select(m_fd + 1, &fds, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
if (n < 0) {
|
||||
LogError("Error from select(), errno=%d", errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (n > 0) {
|
||||
ssize_t len = ::read(m_fd, buffer + offset, length - offset);
|
||||
if (len < 0) {
|
||||
if (errno != EAGAIN) {
|
||||
LogError("Error from read(), errno=%d", errno);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (len > 0)
|
||||
offset += len;
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
int CSerialController::write(const unsigned char* buffer, unsigned int length)
|
||||
{
|
||||
assert(buffer != NULL);
|
||||
assert(m_fd != -1);
|
||||
|
||||
if (length == 0U)
|
||||
return 0;
|
||||
|
||||
unsigned int ptr = 0U;
|
||||
|
||||
while (ptr < length) {
|
||||
ssize_t n = ::write(m_fd, buffer + ptr, length - ptr);
|
||||
if (n < 0) {
|
||||
if (errno != EAGAIN) {
|
||||
LogError("Error returned from write(), errno=%d", errno);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (n > 0)
|
||||
ptr += n;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
void CSerialController::close()
|
||||
{
|
||||
assert(m_fd != -1);
|
||||
|
||||
::close(m_fd);
|
||||
m_fd = -1;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright (C) 2002-2004,2007-2009,2011-2013,2015,2016 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 1999-2001 by Thomas Sailor HB9JNX
|
||||
*
|
||||
* 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 SerialController_H
|
||||
#define SerialController_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
enum SERIAL_SPEED {
|
||||
SERIAL_1200 = 1200,
|
||||
SERIAL_2400 = 2400,
|
||||
SERIAL_4800 = 4800,
|
||||
SERIAL_9600 = 9600,
|
||||
SERIAL_19200 = 19200,
|
||||
SERIAL_38400 = 38400,
|
||||
SERIAL_76800 = 76800,
|
||||
SERIAL_115200 = 115200,
|
||||
SERIAL_230400 = 230400
|
||||
};
|
||||
|
||||
class CSerialController {
|
||||
public:
|
||||
CSerialController(const std::string& device, SERIAL_SPEED speed, bool assertRTS = false);
|
||||
~CSerialController();
|
||||
|
||||
bool open();
|
||||
|
||||
int read(unsigned char* buffer, unsigned int length);
|
||||
int write(const unsigned char* buffer, unsigned int length);
|
||||
|
||||
void close();
|
||||
|
||||
private:
|
||||
std::string m_device;
|
||||
SERIAL_SPEED m_speed;
|
||||
bool m_assertRTS;
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
HANDLE m_handle;
|
||||
OVERLAPPED m_readOverlapped;
|
||||
OVERLAPPED m_writeOverlapped;
|
||||
unsigned char* m_readBuffer;
|
||||
unsigned int m_readLength;
|
||||
bool m_readPending;
|
||||
#else
|
||||
int m_fd;
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
int readNonblock(unsigned char* buffer, unsigned int length);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,220 @@
|
|||
/*
|
||||
* 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 "ShortLC.h"
|
||||
|
||||
#include "Hamming.h"
|
||||
#include "Utils.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
CShortLC::CShortLC() :
|
||||
m_rawData(NULL),
|
||||
m_deInterData(NULL)
|
||||
{
|
||||
m_rawData = new bool[72U];
|
||||
m_deInterData = new bool[68U];
|
||||
}
|
||||
|
||||
CShortLC::~CShortLC()
|
||||
{
|
||||
delete[] m_rawData;
|
||||
delete[] m_deInterData;
|
||||
}
|
||||
|
||||
// The main decode function
|
||||
bool CShortLC::decode(const unsigned char* in, unsigned char* out)
|
||||
{
|
||||
assert(in != NULL);
|
||||
assert(out != NULL);
|
||||
|
||||
// Get the raw binary
|
||||
decodeExtractBinary(in);
|
||||
|
||||
// Deinterleave
|
||||
decodeDeInterleave();
|
||||
|
||||
// Error check
|
||||
bool ret = decodeErrorCheck();
|
||||
if (!ret)
|
||||
return false;
|
||||
|
||||
// Extract Data
|
||||
decodeExtractData(out);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// The main encode function
|
||||
void CShortLC::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 CShortLC::decodeExtractBinary(const unsigned char* in)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
// Deinterleave the raw data
|
||||
void CShortLC::decodeDeInterleave()
|
||||
{
|
||||
for (unsigned int i = 0U; i < 68U; i++)
|
||||
m_deInterData[i] = false;
|
||||
|
||||
for (unsigned int a = 0U; a < 67U; a++) {
|
||||
// Calculate the interleave sequence
|
||||
unsigned int interleaveSequence = (a * 4U) % 67U;
|
||||
// Shuffle the data
|
||||
m_deInterData[a] = m_rawData[interleaveSequence];
|
||||
}
|
||||
|
||||
m_deInterData[67U] = m_rawData[67U];
|
||||
}
|
||||
|
||||
// Check each row with a Hamming (17,12,3) code and each column with a parity bit
|
||||
bool CShortLC::decodeErrorCheck()
|
||||
{
|
||||
// Run through each of the 3 rows containing data
|
||||
CHamming::decode17123(m_deInterData + 0U);
|
||||
CHamming::decode17123(m_deInterData + 17U);
|
||||
CHamming::decode17123(m_deInterData + 34U);
|
||||
|
||||
// Run through each of the 17 columns
|
||||
for (unsigned int c = 0U; c < 17U; c++) {
|
||||
bool bit = m_deInterData[c + 0U] ^ m_deInterData[c + 17U] ^ m_deInterData[c + 34U];
|
||||
if (bit != m_deInterData[c + 51U])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Extract the 36 bits of payload
|
||||
void CShortLC::decodeExtractData(unsigned char* data) const
|
||||
{
|
||||
bool bData[40U];
|
||||
|
||||
for (unsigned int i = 0U; i < 40U; i++)
|
||||
bData[i] = false;
|
||||
|
||||
unsigned int pos = 4U;
|
||||
for (unsigned int a = 0U; a < 12U; a++, pos++)
|
||||
bData[pos] = m_deInterData[a];
|
||||
|
||||
for (unsigned int a = 17U; a < 29U; a++, pos++)
|
||||
bData[pos] = m_deInterData[a];
|
||||
|
||||
for (unsigned int a = 34U; a < 46U; 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]);
|
||||
}
|
||||
|
||||
// Extract the 36 bits of payload
|
||||
void CShortLC::encodeExtractData(const unsigned char* in) const
|
||||
{
|
||||
bool bData[40U];
|
||||
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);
|
||||
|
||||
for (unsigned int i = 0U; i < 68U; i++)
|
||||
m_deInterData[i] = false;
|
||||
|
||||
unsigned int pos = 4U;
|
||||
for (unsigned int a = 0U; a < 12U; a++, pos++)
|
||||
m_deInterData[a] = bData[pos];
|
||||
|
||||
for (unsigned int a = 17U; a < 29U; a++, pos++)
|
||||
m_deInterData[a] = bData[pos];
|
||||
|
||||
for (unsigned int a = 34U; a < 46U; a++, pos++)
|
||||
m_deInterData[a] = bData[pos];
|
||||
}
|
||||
|
||||
// Check each row with a Hamming (17,12,3) code and each column with a parity bit
|
||||
void CShortLC::encodeErrorCheck()
|
||||
{
|
||||
// Run through each of the 3 rows containing data
|
||||
CHamming::encode17123(m_deInterData + 0U);
|
||||
CHamming::encode17123(m_deInterData + 17U);
|
||||
CHamming::encode17123(m_deInterData + 34U);
|
||||
|
||||
// Run through each of the 17 columns
|
||||
for (unsigned int c = 0U; c < 17U; c++)
|
||||
m_deInterData[c + 51U] = m_deInterData[c + 0U] ^ m_deInterData[c + 17U] ^ m_deInterData[c + 34U];
|
||||
}
|
||||
|
||||
// Interleave the raw data
|
||||
void CShortLC::encodeInterleave()
|
||||
{
|
||||
for (unsigned int i = 0U; i < 72U; i++)
|
||||
m_rawData[i] = false;
|
||||
|
||||
for (unsigned int a = 0U; a < 67U; a++) {
|
||||
// Calculate the interleave sequence
|
||||
unsigned int interleaveSequence = (a * 4U) % 67U;
|
||||
// Unshuffle the data
|
||||
m_rawData[interleaveSequence] = m_deInterData[a];
|
||||
}
|
||||
|
||||
m_rawData[67U] = m_deInterData[67U];
|
||||
}
|
||||
|
||||
void CShortLC::encodeExtractBinary(unsigned char* data)
|
||||
{
|
||||
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]);
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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(SHORTLC_H)
|
||||
#define SHORTLC_H
|
||||
|
||||
class CShortLC
|
||||
{
|
||||
public:
|
||||
CShortLC();
|
||||
~CShortLC();
|
||||
|
||||
bool 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);
|
||||
bool 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,92 @@
|
|||
/*
|
||||
* 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 "SlotType.h"
|
||||
|
||||
#include "Golay2087.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
CSlotType::CSlotType() :
|
||||
m_colorCode(0U),
|
||||
m_dataType(0U)
|
||||
{
|
||||
}
|
||||
|
||||
CSlotType::~CSlotType()
|
||||
{
|
||||
}
|
||||
|
||||
void CSlotType::putData(const unsigned char* data)
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
unsigned char slotType[3U];
|
||||
slotType[0U] = (data[12U] << 2) & 0xFCU;
|
||||
slotType[0U] |= (data[13U] >> 6) & 0x03U;
|
||||
|
||||
slotType[1U] = (data[13U] << 2) & 0xC0U;
|
||||
slotType[1U] |= (data[19U] << 2) & 0x3CU;
|
||||
slotType[1U] |= (data[20U] >> 6) & 0x03U;
|
||||
|
||||
slotType[2U] = (data[20U] << 2) & 0xF0U;
|
||||
|
||||
unsigned char code = CGolay2087::decode(slotType);
|
||||
|
||||
m_colorCode = (code >> 4) & 0x0FU;
|
||||
m_dataType = (code >> 0) & 0x0FU;
|
||||
}
|
||||
|
||||
void CSlotType::getData(unsigned char* data) const
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
unsigned char slotType[3U];
|
||||
slotType[0U] = (m_colorCode << 4) & 0xF0U;
|
||||
slotType[0U] |= (m_dataType << 0) & 0x0FU;
|
||||
slotType[1U] = 0x00U;
|
||||
slotType[2U] = 0x00U;
|
||||
|
||||
CGolay2087::encode(slotType);
|
||||
|
||||
data[12U] = (data[12U] & 0xC0U) | ((slotType[0U] >> 2) & 0x3FU);
|
||||
data[13U] = (data[13U] & 0x0FU) | ((slotType[0U] << 6) & 0xC0U) | ((slotType[1U] >> 2) & 0x30U);
|
||||
data[19U] = (data[19U] & 0xF0U) | ((slotType[1U] >> 2) & 0x0FU);
|
||||
data[20U] = (data[20U] & 0x03U) | ((slotType[1U] << 6) & 0xC0U) | ((slotType[2U] >> 2) & 0x3CU);
|
||||
}
|
||||
|
||||
unsigned char CSlotType::getColorCode() const
|
||||
{
|
||||
return m_colorCode;
|
||||
}
|
||||
|
||||
void CSlotType::setColorCode(unsigned char code)
|
||||
{
|
||||
m_colorCode = code;
|
||||
}
|
||||
|
||||
unsigned char CSlotType::getDataType() const
|
||||
{
|
||||
return m_dataType;
|
||||
}
|
||||
|
||||
void CSlotType::setDataType(unsigned char type)
|
||||
{
|
||||
m_dataType = type;
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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(SLOTTYPE_H)
|
||||
#define SLOTTYPE_H
|
||||
|
||||
class CSlotType
|
||||
{
|
||||
public:
|
||||
CSlotType();
|
||||
~CSlotType();
|
||||
|
||||
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,85 @@
|
|||
/*
|
||||
* 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 "StopWatch.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
|
||||
CStopWatch::CStopWatch() :
|
||||
m_frequency(),
|
||||
m_start()
|
||||
{
|
||||
::QueryPerformanceFrequency(&m_frequency);
|
||||
}
|
||||
|
||||
CStopWatch::~CStopWatch()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned long CStopWatch::start()
|
||||
{
|
||||
::QueryPerformanceCounter(&m_start);
|
||||
|
||||
return (unsigned long)(m_start.QuadPart / m_frequency.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_frequency.QuadPart);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
CStopWatch::CStopWatch() :
|
||||
m_start()
|
||||
{
|
||||
}
|
||||
|
||||
CStopWatch::~CStopWatch()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned long CStopWatch::start()
|
||||
{
|
||||
::clock_gettime(CLOCK_MONOTONIC, &m_start);
|
||||
|
||||
return m_start.tv_nsec;
|
||||
}
|
||||
|
||||
unsigned int CStopWatch::elapsed()
|
||||
{
|
||||
timespec now;
|
||||
::clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
||||
if (m_start.tv_sec == now.tv_sec) {
|
||||
return (now.tv_nsec - m_start.tv_nsec) / 1000000U;
|
||||
} else {
|
||||
long temp = -m_start.tv_nsec / 1000000L;
|
||||
temp += (now.tv_sec - m_start.tv_sec) * 1000L;
|
||||
temp += m_start.tv_nsec / 1000000L;
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -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(STOPWATCH_H)
|
||||
#define STOPWATCH_H
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <ctime>
|
||||
#endif
|
||||
|
||||
class CStopWatch
|
||||
{
|
||||
public:
|
||||
CStopWatch();
|
||||
~CStopWatch();
|
||||
|
||||
unsigned long start();
|
||||
unsigned int elapsed();
|
||||
|
||||
private:
|
||||
#if defined(WIN32)
|
||||
LARGE_INTEGER m_frequency;
|
||||
LARGE_INTEGER m_start;
|
||||
#else
|
||||
timespec m_start;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* 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 "TFTSerial.h"
|
||||
#include "Log.h"
|
||||
|
||||
CTFTSerial::CTFTSerial(const std::string& port) :
|
||||
m_serial(port, SERIAL_9600)
|
||||
{
|
||||
}
|
||||
|
||||
CTFTSerial::~CTFTSerial()
|
||||
{
|
||||
}
|
||||
|
||||
bool CTFTSerial::open()
|
||||
{
|
||||
bool ret = m_serial.open();
|
||||
if (!ret) {
|
||||
LogError("Cannot open the port for the TFT Serial");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set background white
|
||||
m_serial.write((unsigned char*)"\x1B\x02\x07\xFF", 4U);
|
||||
|
||||
// Set foreground black
|
||||
m_serial.write((unsigned char*)"\x1B\x01\x00\xFF", 4U);
|
||||
|
||||
setIdle();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CTFTSerial::setIdle()
|
||||
{
|
||||
// Clear the screen
|
||||
m_serial.write((unsigned char*)"\x1B\x00\xFF", 3U);
|
||||
|
||||
// Draw MMDVM logo
|
||||
m_serial.write((unsigned char*)"\x1B\x0D\x00\x00MMDVM_sm.bmp\xFF", 15U);
|
||||
|
||||
// Draw all mode insignias
|
||||
m_serial.write((unsigned char*)"\x1B\x0D\x00\x00ALL_sm.bmp\xFF", 15U);
|
||||
}
|
||||
|
||||
void CTFTSerial::setDStar()
|
||||
{
|
||||
// Clear the screen
|
||||
m_serial.write((unsigned char*)"\x1B\x00\xFF", 3U);
|
||||
|
||||
// Draw MMDVM logo
|
||||
m_serial.write((unsigned char*)"\x1B\x0D\x00\x00MMDVM_sm.bmp\xFF", 15U);
|
||||
|
||||
// Draw D-Star insignia
|
||||
m_serial.write((unsigned char*)"\x1B\x0D\x00\x00DStar_sm.bmp\xFF", 17U);
|
||||
|
||||
m_serial.write((unsigned char*)"\x1B\x06\x00\x08\xFF", 5U);
|
||||
m_serial.write((unsigned char*)"Listening", 9U);
|
||||
}
|
||||
|
||||
void CTFTSerial::writeDStar(const std::string& call1, const std::string& call2)
|
||||
{
|
||||
m_serial.write((unsigned char*)"\x1B\x06\x00\x08\xFF", 5U);
|
||||
|
||||
char text[20U];
|
||||
::sprintf(text, "%s/%s", call1.c_str(), call2.c_str());
|
||||
|
||||
m_serial.write((unsigned char*)text, ::strlen(text));
|
||||
}
|
||||
|
||||
void CTFTSerial::clearDStar()
|
||||
{
|
||||
// Draw MMDVM logo
|
||||
m_serial.write((unsigned char*)"\x1B\x0D\x00\x00MMDVM_sm.bmp\xFF", 15U);
|
||||
|
||||
// Draw D-Star insignia
|
||||
m_serial.write((unsigned char*)"\x1B\x0D\x00\x00DStar_sm.bmp\xFF", 17U);
|
||||
|
||||
m_serial.write((unsigned char*)"\x1B\x06\x00\x08\xFF", 5U);
|
||||
m_serial.write((unsigned char*)"Listening", 9U);
|
||||
}
|
||||
|
||||
void CTFTSerial::setDMR()
|
||||
{
|
||||
// Clear the screen
|
||||
m_serial.write((unsigned char*)"\x1B\x00\xFF", 3U);
|
||||
|
||||
// Draw MMDVM logo
|
||||
m_serial.write((unsigned char*)"\x1B\x0D\x00\x00MMDVM_sm.bmp\xFF", 15U);
|
||||
|
||||
// Draw DMR insignia
|
||||
m_serial.write((unsigned char*)"\x1B\x0D\x00\x00DMR_sm.bmp\xFF", 15U);
|
||||
|
||||
m_serial.write((unsigned char*)"\x1B\x06\x00\x08\xFF", 5U);
|
||||
m_serial.write((unsigned char*)"1: Listening", 9U);
|
||||
|
||||
m_serial.write((unsigned char*)"\x1B\x06\x00\x09\xFF", 5U);
|
||||
m_serial.write((unsigned char*)"2: Listening", 9U);
|
||||
}
|
||||
|
||||
void CTFTSerial::writeDMR(unsigned int slotNo, unsigned int srcId, bool group, unsigned int dstId)
|
||||
{
|
||||
char text[20U];
|
||||
::sprintf(text, "%u: %u %s%u", slotNo, srcId, group ? "TG " : "", dstId);
|
||||
|
||||
if (slotNo == 1U)
|
||||
m_serial.write((unsigned char*)"\x1B\x06\x00\x08\xFF", 5U);
|
||||
else
|
||||
m_serial.write((unsigned char*)"\x1B\x06\x00\x09\xFF", 5U);
|
||||
|
||||
m_serial.write((unsigned char*)text, ::strlen(text));
|
||||
}
|
||||
|
||||
void CTFTSerial::clearDMR(unsigned int slotNo)
|
||||
{
|
||||
if (slotNo == 1U) {
|
||||
m_serial.write((unsigned char*)"\x1B\x06\x00\x08\xFF", 5U);
|
||||
m_serial.write((unsigned char*)"1: Listening", 11U);
|
||||
} else {
|
||||
m_serial.write((unsigned char*)"\x1B\x06\x00\x09\xFF", 5U);
|
||||
m_serial.write((unsigned char*)"2: Listening", 11U);
|
||||
}
|
||||
}
|
||||
|
||||
void CTFTSerial::setFusion()
|
||||
{
|
||||
// Clear the screen
|
||||
m_serial.write((unsigned char*)"\x1B\x00\xFF", 3U);
|
||||
|
||||
// Draw MMDVM logo
|
||||
m_serial.write((unsigned char*)"\x1B\x0D\x00\x00MMDVM_sm.bmp\xFF", 15U);
|
||||
|
||||
// Draw the System Fusion insignia
|
||||
m_serial.write((unsigned char*)"\x1B\x0D\x00\x00YSF_sm.bmp\xFF", 15U);
|
||||
|
||||
m_serial.write((unsigned char*)"\x1B\x06\x00\x08\xFF", 5U);
|
||||
m_serial.write((unsigned char*)"Listening", 9U);
|
||||
}
|
||||
|
||||
void CTFTSerial::writeFusion(const std::string& callsign)
|
||||
{
|
||||
m_serial.write((unsigned char*)"\x1B\x06\x00\x08\xFF", 5U);
|
||||
|
||||
char text[20U];
|
||||
::sprintf(text, "%s", callsign.c_str());
|
||||
|
||||
m_serial.write((unsigned char*)text, ::strlen(text));
|
||||
}
|
||||
|
||||
void CTFTSerial::clearFusion()
|
||||
{
|
||||
// Draw MMDVM logo
|
||||
m_serial.write((unsigned char*)"\x1B\x0D\x00\x00MMDVM_sm.bmp\xFF", 15U);
|
||||
|
||||
// Draw the System Fusion insignia
|
||||
m_serial.write((unsigned char*)"\x1B\x0D\x00\x00YSF_sm.bmp\xFF", 15U);
|
||||
|
||||
m_serial.write((unsigned char*)"\x1B\x06\x00\x08\xFF", 5U);
|
||||
m_serial.write((unsigned char*)"Listening", 9U);
|
||||
}
|
||||
|
||||
void CTFTSerial::close()
|
||||
{
|
||||
m_serial.close();
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* 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(TFTSERIAL_H)
|
||||
#define TFTSERIAL_H
|
||||
|
||||
#include "Display.h"
|
||||
#include "SerialController.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class CTFTSerial : public IDisplay
|
||||
{
|
||||
public:
|
||||
CTFTSerial(const std::string& port);
|
||||
virtual ~CTFTSerial();
|
||||
|
||||
virtual bool open();
|
||||
|
||||
virtual void setIdle();
|
||||
|
||||
virtual void setDStar();
|
||||
virtual void writeDStar(const std::string& call1, const std::string& call2);
|
||||
virtual void clearDStar();
|
||||
|
||||
virtual void setDMR();
|
||||
virtual void writeDMR(unsigned int slotNo, unsigned int srdId, bool group, unsigned int dstId);
|
||||
virtual void clearDMR(unsigned int slotNo);
|
||||
|
||||
virtual void setFusion();
|
||||
virtual void writeFusion(const std::string& callsign);
|
||||
virtual void clearFusion();
|
||||
|
||||
virtual void close();
|
||||
|
||||
private:
|
||||
CSerialController m_serial;
|
||||
};
|
||||
|
||||
#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,263 @@
|
|||
/*
|
||||
* 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());
|
||||
assert(port > 0U);
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
WSAData data;
|
||||
int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data);
|
||||
if (wsaRet != 0)
|
||||
LogError("Error from WSAStartup");
|
||||
#endif
|
||||
}
|
||||
|
||||
CUDPSocket::CUDPSocket() :
|
||||
m_address(),
|
||||
m_port(0U),
|
||||
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);
|
||||
CUDPSocket();
|
||||
~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,138 @@
|
|||
/*
|
||||
* Copyright (C) 2009,2014,2015 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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,24 @@
|
|||
/*
|
||||
* 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(VERSION_H)
|
||||
#define VERSION_H
|
||||
|
||||
const char* VERSION = "20160113";
|
||||
|
||||
#endif
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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(YSFDefines_H)
|
||||
#define YSFDefines_H
|
||||
|
||||
const unsigned int YSF_FRAME_LENGTH_BYTES = 120U;
|
||||
|
||||
const unsigned char YSF_SYNC_BYTES[] = {0xD4U, 0x71U, 0xC9U, 0x63U, 0x4DU};
|
||||
|
||||
const unsigned char YSF_FI_MASK = 0xC0U;
|
||||
const unsigned char YSF_DT_MASK = 0x30U;
|
||||
|
||||
const unsigned char YSF_DT_TERMINATOR_CHANNEL = 0x80U;
|
||||
|
||||
const unsigned char YSF_CKSUM_OK = 0x01U;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* 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 "YSFEcho.h"
|
||||
|
||||
#include "YSFDefines.h"
|
||||
|
||||
CYSFEcho::CYSFEcho(unsigned int delay, unsigned int space) :
|
||||
m_buffer(space),
|
||||
m_timer(1000U, delay)
|
||||
{
|
||||
}
|
||||
|
||||
CYSFEcho::~CYSFEcho()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned int CYSFEcho::readData(unsigned char* data)
|
||||
{
|
||||
if (!hasData())
|
||||
return 0U;
|
||||
|
||||
unsigned char len;
|
||||
m_buffer.getData(&len, 1U);
|
||||
|
||||
m_buffer.getData(data, len);
|
||||
|
||||
// If the FICH is valid, regenerate the sync
|
||||
if ((data[1U] & 0x01U) == 0x01U) {
|
||||
data[2U] = YSF_SYNC_BYTES[0U];
|
||||
data[3U] = YSF_SYNC_BYTES[1U];
|
||||
data[4U] = YSF_SYNC_BYTES[2U];
|
||||
data[5U] = YSF_SYNC_BYTES[3U];
|
||||
data[6U] = YSF_SYNC_BYTES[4U];
|
||||
}
|
||||
|
||||
if (!hasData())
|
||||
m_timer.stop();
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
bool CYSFEcho::writeData(const unsigned char* data, unsigned int length)
|
||||
{
|
||||
bool ret = m_buffer.hasSpace(length + 1U);
|
||||
if (!ret)
|
||||
return false;
|
||||
|
||||
unsigned char len = length;
|
||||
m_buffer.addData(&len, 1U);
|
||||
|
||||
m_buffer.addData(data, length);
|
||||
|
||||
m_timer.start();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CYSFEcho::hasData()
|
||||
{
|
||||
if (m_timer.isRunning() && m_timer.hasExpired())
|
||||
return m_buffer.hasData();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void CYSFEcho::clock(unsigned int ms)
|
||||
{
|
||||
m_timer.clock(ms);
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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(YSFECHO_H)
|
||||
#define YSFECHO_H
|
||||
|
||||
#include "RingBuffer.h"
|
||||
#include "Timer.h"
|
||||
|
||||
class CYSFEcho {
|
||||
public:
|
||||
CYSFEcho(unsigned int delay, unsigned int space);
|
||||
~CYSFEcho();
|
||||
|
||||
unsigned int readData(unsigned char* data);
|
||||
|
||||
bool writeData(const unsigned char* data, unsigned int length);
|
||||
|
||||
bool hasData();
|
||||
|
||||
void clock(unsigned int ms);
|
||||
|
||||
private:
|
||||
CRingBuffer<unsigned char> m_buffer;
|
||||
CTimer m_timer;
|
||||
};
|
||||
|
||||
#endif
|