6
.gitignore
vendored
|
@ -1,6 +1,9 @@
|
||||||
Debug
|
Debug
|
||||||
Release
|
Release
|
||||||
x64
|
x64
|
||||||
|
MMDVMHost
|
||||||
|
RemoteCommand
|
||||||
|
*.o
|
||||||
*.opendb
|
*.opendb
|
||||||
*.bak
|
*.bak
|
||||||
*.obj
|
*.obj
|
||||||
|
@ -10,4 +13,7 @@ x64
|
||||||
*.zip
|
*.zip
|
||||||
*.exe
|
*.exe
|
||||||
*.user
|
*.user
|
||||||
|
*.VC.db
|
||||||
.vs
|
.vs
|
||||||
|
*.ambe
|
||||||
|
GitVersion.h
|
||||||
|
|
396
AMBEFEC.cpp
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2010,2014,2016 by Jonathan Naylor G4KLX
|
* Copyright (C) 2010,2014,2016,2018 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2016 Mathias Weyland, HB9FRV
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,11 +17,11 @@
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "Golay24128.h"
|
||||||
|
#include "Hamming.h"
|
||||||
#include "AMBEFEC.h"
|
#include "AMBEFEC.h"
|
||||||
|
|
||||||
#include "Log.h" // XXX
|
#include <cstdio>
|
||||||
|
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
const unsigned char BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U};
|
const unsigned char BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U};
|
||||||
|
@ -28,10 +29,6 @@ const unsigned char BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U
|
||||||
#define WRITE_BIT(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7])
|
#define WRITE_BIT(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7])
|
||||||
#define READ_BIT(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
|
#define READ_BIT(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
|
||||||
|
|
||||||
const unsigned int PRNG_TABLE_DMR[] = {
|
|
||||||
0x00
|
|
||||||
};
|
|
||||||
|
|
||||||
const unsigned int PRNG_TABLE[] = {
|
const unsigned int PRNG_TABLE[] = {
|
||||||
0x42CC47U, 0x19D6FEU, 0x304729U, 0x6B2CD0U, 0x60BF47U, 0x39650EU, 0x7354F1U, 0xEACF60U, 0x819C9FU, 0xDE25CEU,
|
0x42CC47U, 0x19D6FEU, 0x304729U, 0x6B2CD0U, 0x60BF47U, 0x39650EU, 0x7354F1U, 0xEACF60U, 0x819C9FU, 0xDE25CEU,
|
||||||
0xD7B745U, 0x8CC8B8U, 0x8D592BU, 0xF71257U, 0xBCA084U, 0xA5B329U, 0xEE6AFAU, 0xF7D9A7U, 0xBCC21CU, 0x4712D9U,
|
0xD7B745U, 0x8CC8B8U, 0x8D592BU, 0xF71257U, 0xBCA084U, 0xA5B329U, 0xEE6AFAU, 0xF7D9A7U, 0xBCC21CU, 0x4712D9U,
|
||||||
|
@ -444,9 +441,12 @@ const unsigned int PRNG_TABLE[] = {
|
||||||
0xECDB0FU, 0xB542DAU, 0x9E5131U, 0xC7ABA5U, 0x8C38FEU, 0x97010BU, 0xDED290U, 0xA4CC7DU, 0xAD3D2EU, 0xF6B6B3U,
|
0xECDB0FU, 0xB542DAU, 0x9E5131U, 0xC7ABA5U, 0x8C38FEU, 0x97010BU, 0xDED290U, 0xA4CC7DU, 0xAD3D2EU, 0xF6B6B3U,
|
||||||
0xF9A540U, 0x205ED9U, 0x634EB6U, 0x5A9567U, 0x11A6D8U, 0x0B3F09U};
|
0xF9A540U, 0x205ED9U, 0x634EB6U, 0x5A9567U, 0x11A6D8U, 0x0B3F09U};
|
||||||
|
|
||||||
const unsigned int DMR_A_TABLE[] = {0U};
|
const unsigned int DMR_A_TABLE[] = { 0U, 4U, 8U, 12U, 16U, 20U, 24U, 28U, 32U, 36U, 40U, 44U,
|
||||||
const unsigned int DMR_B_TABLE[] = { 0U };
|
48U, 52U, 56U, 60U, 64U, 68U, 1U, 5U, 9U, 13U, 17U, 21U};
|
||||||
const unsigned int DMR_C_TABLE[] = { 0U };
|
const unsigned int DMR_B_TABLE[] = {25U, 29U, 33U, 37U, 41U, 45U, 49U, 53U, 57U, 61U, 65U, 69U,
|
||||||
|
2U, 6U, 10U, 14U, 18U, 22U, 26U, 30U, 34U, 38U, 42U};
|
||||||
|
const unsigned int DMR_C_TABLE[] = {46U, 50U, 54U, 58U, 62U, 66U, 70U, 3U, 7U, 11U, 15U, 19U,
|
||||||
|
23U, 27U, 31U, 35U, 39U, 43U, 47U, 51U, 55U, 59U, 63U, 67U, 71U};
|
||||||
|
|
||||||
const unsigned int DSTAR_A_TABLE[] = {0U, 6U, 12U, 18U, 24U, 30U, 36U, 42U, 48U, 54U, 60U, 66U,
|
const unsigned int DSTAR_A_TABLE[] = {0U, 6U, 12U, 18U, 24U, 30U, 36U, 42U, 48U, 54U, 60U, 66U,
|
||||||
1U, 7U, 13U, 19U, 25U, 31U, 37U, 43U, 49U, 55U, 61U, 67U};
|
1U, 7U, 13U, 19U, 25U, 31U, 37U, 43U, 49U, 55U, 61U, 67U};
|
||||||
|
@ -455,6 +455,15 @@ const unsigned int DSTAR_B_TABLE[] = {2U, 8U, 14U, 20U, 26U, 32U, 38U, 44U, 50U
|
||||||
const unsigned int DSTAR_C_TABLE[] = {4U, 10U, 16U, 22U, 28U, 34U, 40U, 46U, 52U, 58U, 64U, 70U,
|
const unsigned int DSTAR_C_TABLE[] = {4U, 10U, 16U, 22U, 28U, 34U, 40U, 46U, 52U, 58U, 64U, 70U,
|
||||||
5U, 11U, 17U, 23U, 29U, 35U, 41U, 47U, 53U, 59U, 65U, 71U};
|
5U, 11U, 17U, 23U, 29U, 35U, 41U, 47U, 53U, 59U, 65U, 71U};
|
||||||
|
|
||||||
|
const unsigned int IMBE_INTERLEAVE[] = {
|
||||||
|
0, 7, 12, 19, 24, 31, 36, 43, 48, 55, 60, 67, 72, 79, 84, 91, 96, 103, 108, 115, 120, 127, 132, 139,
|
||||||
|
1, 6, 13, 18, 25, 30, 37, 42, 49, 54, 61, 66, 73, 78, 85, 90, 97, 102, 109, 114, 121, 126, 133, 138,
|
||||||
|
2, 9, 14, 21, 26, 33, 38, 45, 50, 57, 62, 69, 74, 81, 86, 93, 98, 105, 110, 117, 122, 129, 134, 141,
|
||||||
|
3, 8, 15, 20, 27, 32, 39, 44, 51, 56, 63, 68, 75, 80, 87, 92, 99, 104, 111, 116, 123, 128, 135, 140,
|
||||||
|
4, 11, 16, 23, 28, 35, 40, 47, 52, 59, 64, 71, 76, 83, 88, 95, 100, 107, 112, 119, 124, 131, 136, 143,
|
||||||
|
5, 10, 17, 22, 29, 34, 41, 46, 53, 58, 65, 70, 77, 82, 89, 94, 101, 106, 113, 118, 125, 130, 137, 142
|
||||||
|
};
|
||||||
|
|
||||||
CAMBEFEC::CAMBEFEC()
|
CAMBEFEC::CAMBEFEC()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -467,31 +476,14 @@ unsigned int CAMBEFEC::regenerateDMR(unsigned char* bytes) const
|
||||||
{
|
{
|
||||||
assert(bytes != NULL);
|
assert(bytes != NULL);
|
||||||
|
|
||||||
return 0U;
|
|
||||||
|
|
||||||
unsigned int a1 = 0U, a2 = 0U, a3 = 0U;
|
unsigned int a1 = 0U, a2 = 0U, a3 = 0U;
|
||||||
unsigned int b1 = 0U, b2 = 0U, b3 = 0U;
|
|
||||||
unsigned int c1 = 0U, c2 = 0U, c3 = 0U;
|
|
||||||
|
|
||||||
unsigned int MASK = 0x800000U;
|
unsigned int MASK = 0x800000U;
|
||||||
for (unsigned int i = 0U; i < 24U; i++) {
|
for (unsigned int i = 0U; i < 24U; i++, MASK >>= 1) {
|
||||||
unsigned int a1Pos = DMR_A_TABLE[i];
|
unsigned int a1Pos = DMR_A_TABLE[i];
|
||||||
unsigned int b1Pos = DMR_B_TABLE[i];
|
|
||||||
unsigned int c1Pos = DMR_C_TABLE[i];
|
|
||||||
|
|
||||||
unsigned int a2Pos = a1Pos + 72U;
|
unsigned int a2Pos = a1Pos + 72U;
|
||||||
if (a2Pos >= 108U)
|
if (a2Pos >= 108U)
|
||||||
a2Pos += 48U;
|
a2Pos += 48U;
|
||||||
unsigned int b2Pos = b1Pos + 72U;
|
|
||||||
if (b2Pos >= 108U)
|
|
||||||
b2Pos += 48U;
|
|
||||||
unsigned int c2Pos = c1Pos + 72U;
|
|
||||||
if (c2Pos >= 108U)
|
|
||||||
c2Pos += 48U;
|
|
||||||
|
|
||||||
unsigned int a3Pos = a1Pos + 192U;
|
unsigned int a3Pos = a1Pos + 192U;
|
||||||
unsigned int b3Pos = b1Pos + 192U;
|
|
||||||
unsigned int c3Pos = c1Pos + 192U;
|
|
||||||
|
|
||||||
if (READ_BIT(bytes, a1Pos))
|
if (READ_BIT(bytes, a1Pos))
|
||||||
a1 |= MASK;
|
a1 |= MASK;
|
||||||
|
@ -499,71 +491,83 @@ unsigned int CAMBEFEC::regenerateDMR(unsigned char* bytes) const
|
||||||
a2 |= MASK;
|
a2 |= MASK;
|
||||||
if (READ_BIT(bytes, a3Pos))
|
if (READ_BIT(bytes, a3Pos))
|
||||||
a3 |= MASK;
|
a3 |= MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int b1 = 0U, b2 = 0U, b3 = 0U;
|
||||||
|
MASK = 0x400000U;
|
||||||
|
for (unsigned int i = 0U; i < 23U; i++, MASK >>= 1) {
|
||||||
|
unsigned int b1Pos = DMR_B_TABLE[i];
|
||||||
|
unsigned int b2Pos = b1Pos + 72U;
|
||||||
|
if (b2Pos >= 108U)
|
||||||
|
b2Pos += 48U;
|
||||||
|
unsigned int b3Pos = b1Pos + 192U;
|
||||||
|
|
||||||
if (READ_BIT(bytes, b1Pos))
|
if (READ_BIT(bytes, b1Pos))
|
||||||
b1 |= MASK;
|
b1 |= MASK;
|
||||||
if (READ_BIT(bytes, b2Pos))
|
if (READ_BIT(bytes, b2Pos))
|
||||||
b2 |= MASK;
|
b2 |= MASK;
|
||||||
if (READ_BIT(bytes, b3Pos))
|
if (READ_BIT(bytes, b3Pos))
|
||||||
b3 |= MASK;
|
b3 |= MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int c1 = 0U, c2 = 0U, c3 = 0U;
|
||||||
|
MASK = 0x1000000U;
|
||||||
|
for (unsigned int i = 0U; i < 25U; i++, MASK >>= 1) {
|
||||||
|
unsigned int c1Pos = DMR_C_TABLE[i];
|
||||||
|
unsigned int c2Pos = c1Pos + 72U;
|
||||||
|
if (c2Pos >= 108U)
|
||||||
|
c2Pos += 48U;
|
||||||
|
unsigned int c3Pos = c1Pos + 192U;
|
||||||
|
|
||||||
if (READ_BIT(bytes, c1Pos))
|
if (READ_BIT(bytes, c1Pos))
|
||||||
c1 |= MASK;
|
c1 |= MASK;
|
||||||
if (READ_BIT(bytes, c2Pos))
|
if (READ_BIT(bytes, c2Pos))
|
||||||
c2 |= MASK;
|
c2 |= MASK;
|
||||||
if (READ_BIT(bytes, c3Pos))
|
if (READ_BIT(bytes, c3Pos))
|
||||||
c3 |= MASK;
|
c3 |= MASK;
|
||||||
|
|
||||||
MASK >>= 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int old_a1 = a1;
|
unsigned int errors = regenerateDMR(a1, b1, c1);
|
||||||
unsigned int data = CGolay24128::decode24128(a1);
|
errors += regenerateDMR(a2, b2, c2);
|
||||||
|
errors += regenerateDMR(a3, b3, c3);
|
||||||
unsigned int new_a1 = CGolay24128::encode24128(data);
|
|
||||||
|
|
||||||
unsigned int errors = 0U;
|
|
||||||
unsigned int mask = 0x01;
|
|
||||||
for (unsigned int i = 0U; i < 24U; i++, mask <<= 1) {
|
|
||||||
if ((old_a1 & mask) != (new_a1 & mask))
|
|
||||||
errors++;
|
|
||||||
}
|
|
||||||
|
|
||||||
LogMessage("FEC: Old/New: %06X %06X Diff: %06X, errs: %u", old_a1, new_a1, old_a1 ^ new_a1, errors);
|
|
||||||
|
|
||||||
// unsigned int errors = regenerate(a1, b1, c1);
|
|
||||||
// errors += regenerate(a2, b2, c2);
|
|
||||||
// errors += regenerate(a3, b3, c3);
|
|
||||||
|
|
||||||
MASK = 0x800000U;
|
MASK = 0x800000U;
|
||||||
for (unsigned int i = 0U; i < 24U; i++) {
|
for (unsigned int i = 0U; i < 24U; i++, MASK >>= 1) {
|
||||||
unsigned int a1Pos = DMR_A_TABLE[i];
|
unsigned int a1Pos = DMR_A_TABLE[i];
|
||||||
unsigned int b1Pos = DMR_B_TABLE[i];
|
|
||||||
unsigned int c1Pos = DMR_C_TABLE[i];
|
|
||||||
|
|
||||||
unsigned int a2Pos = a1Pos + 72U;
|
unsigned int a2Pos = a1Pos + 72U;
|
||||||
if (a2Pos >= 108U)
|
if (a2Pos >= 108U)
|
||||||
a2Pos += 48U;
|
a2Pos += 48U;
|
||||||
unsigned int b2Pos = b1Pos + 72U;
|
|
||||||
if (b2Pos >= 108U)
|
|
||||||
b2Pos += 48U;
|
|
||||||
unsigned int c2Pos = c1Pos + 72U;
|
|
||||||
if (c2Pos >= 108U)
|
|
||||||
c2Pos += 48U;
|
|
||||||
|
|
||||||
unsigned int a3Pos = a1Pos + 192U;
|
unsigned int a3Pos = a1Pos + 192U;
|
||||||
unsigned int b3Pos = b1Pos + 192U;
|
|
||||||
unsigned int c3Pos = c1Pos + 192U;
|
|
||||||
|
|
||||||
WRITE_BIT(bytes, a1Pos, a1 & MASK);
|
WRITE_BIT(bytes, a1Pos, a1 & MASK);
|
||||||
WRITE_BIT(bytes, a2Pos, a2 & MASK);
|
WRITE_BIT(bytes, a2Pos, a2 & MASK);
|
||||||
WRITE_BIT(bytes, a3Pos, a3 & MASK);
|
WRITE_BIT(bytes, a3Pos, a3 & MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
MASK = 0x400000U;
|
||||||
|
for (unsigned int i = 0U; i < 23U; i++, MASK >>= 1) {
|
||||||
|
unsigned int b1Pos = DMR_B_TABLE[i];
|
||||||
|
unsigned int b2Pos = b1Pos + 72U;
|
||||||
|
if (b2Pos >= 108U)
|
||||||
|
b2Pos += 48U;
|
||||||
|
unsigned int b3Pos = b1Pos + 192U;
|
||||||
|
|
||||||
WRITE_BIT(bytes, b1Pos, b1 & MASK);
|
WRITE_BIT(bytes, b1Pos, b1 & MASK);
|
||||||
WRITE_BIT(bytes, b2Pos, b2 & MASK);
|
WRITE_BIT(bytes, b2Pos, b2 & MASK);
|
||||||
WRITE_BIT(bytes, b3Pos, b3 & MASK);
|
WRITE_BIT(bytes, b3Pos, b3 & MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
MASK = 0x1000000U;
|
||||||
|
for (unsigned int i = 0U; i < 25U; i++, MASK >>= 1) {
|
||||||
|
unsigned int c1Pos = DMR_C_TABLE[i];
|
||||||
|
unsigned int c2Pos = c1Pos + 72U;
|
||||||
|
if (c2Pos >= 108U)
|
||||||
|
c2Pos += 48U;
|
||||||
|
unsigned int c3Pos = c1Pos + 192U;
|
||||||
|
|
||||||
WRITE_BIT(bytes, c1Pos, c1 & MASK);
|
WRITE_BIT(bytes, c1Pos, c1 & MASK);
|
||||||
WRITE_BIT(bytes, c2Pos, c2 & MASK);
|
WRITE_BIT(bytes, c2Pos, c2 & MASK);
|
||||||
WRITE_BIT(bytes, c3Pos, c3 & MASK);
|
WRITE_BIT(bytes, c3Pos, c3 & MASK);
|
||||||
|
|
||||||
MASK >>= 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors;
|
return errors;
|
||||||
|
@ -588,7 +592,7 @@ unsigned int CAMBEFEC::regenerateDStar(unsigned char* bytes) const
|
||||||
MASK >>= 1;
|
MASK >>= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int errors = regenerate(a, b, c);
|
unsigned int errors = regenerateDStar(a, b);
|
||||||
|
|
||||||
MASK = 0x800000U;
|
MASK = 0x800000U;
|
||||||
for (unsigned int i = 0U; i < 24U; i++) {
|
for (unsigned int i = 0U; i < 24U; i++) {
|
||||||
|
@ -601,14 +605,199 @@ unsigned int CAMBEFEC::regenerateDStar(unsigned char* bytes) const
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int CAMBEFEC::regenerate(unsigned int& a, unsigned int& b, unsigned int& c) const
|
unsigned int CAMBEFEC::regenerateYSFDN(unsigned char* bytes) const
|
||||||
{
|
{
|
||||||
unsigned int old_a = a;
|
assert(bytes != NULL);
|
||||||
unsigned int old_b = b;
|
|
||||||
|
unsigned int a = 0U;
|
||||||
|
unsigned int MASK = 0x800000U;
|
||||||
|
for (unsigned int i = 0U; i < 24U; i++, MASK >>= 1) {
|
||||||
|
unsigned int aPos = DMR_A_TABLE[i];
|
||||||
|
if (READ_BIT(bytes, aPos))
|
||||||
|
a |= MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int b = 0U;
|
||||||
|
MASK = 0x400000U;
|
||||||
|
for (unsigned int i = 0U; i < 23U; i++, MASK >>= 1) {
|
||||||
|
unsigned int bPos = DMR_B_TABLE[i];
|
||||||
|
if (READ_BIT(bytes, bPos))
|
||||||
|
b |= MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int c = 0U;
|
||||||
|
MASK = 0x1000000U;
|
||||||
|
for (unsigned int i = 0U; i < 25U; i++, MASK >>= 1) {
|
||||||
|
unsigned int cPos = DMR_C_TABLE[i];
|
||||||
|
if (READ_BIT(bytes, cPos))
|
||||||
|
c |= MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int errors = regenerateDMR(a, b, c);
|
||||||
|
|
||||||
|
MASK = 0x800000U;
|
||||||
|
for (unsigned int i = 0U; i < 24U; i++, MASK >>= 1) {
|
||||||
|
unsigned int aPos = DMR_A_TABLE[i];
|
||||||
|
WRITE_BIT(bytes, aPos, a & MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
MASK = 0x400000U;
|
||||||
|
for (unsigned int i = 0U; i < 23U; i++, MASK >>= 1) {
|
||||||
|
unsigned int bPos = DMR_B_TABLE[i];
|
||||||
|
WRITE_BIT(bytes, bPos, b & MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
MASK = 0x1000000U;
|
||||||
|
for (unsigned int i = 0U; i < 25U; i++, MASK >>= 1) {
|
||||||
|
unsigned int cPos = DMR_C_TABLE[i];
|
||||||
|
WRITE_BIT(bytes, cPos, c & MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CAMBEFEC::regenerateIMBE(unsigned char* bytes) const
|
||||||
|
{
|
||||||
|
assert(bytes != NULL);
|
||||||
|
|
||||||
|
bool orig[144U];
|
||||||
|
bool temp[144U];
|
||||||
|
|
||||||
|
// De-interleave
|
||||||
|
for (unsigned int i = 0U; i < 144U; i++) {
|
||||||
|
unsigned int n = IMBE_INTERLEAVE[i];
|
||||||
|
orig[i] = temp[i] = READ_BIT(bytes, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
// now ..
|
||||||
|
|
||||||
|
// 12 voice bits 0
|
||||||
|
// 11 golay bits 12
|
||||||
|
//
|
||||||
|
// 12 voice bits 23
|
||||||
|
// 11 golay bits 35
|
||||||
|
//
|
||||||
|
// 12 voice bits 46
|
||||||
|
// 11 golay bits 58
|
||||||
|
//
|
||||||
|
// 12 voice bits 69
|
||||||
|
// 11 golay bits 81
|
||||||
|
//
|
||||||
|
// 11 voice bits 92
|
||||||
|
// 4 hamming bits 103
|
||||||
|
//
|
||||||
|
// 11 voice bits 107
|
||||||
|
// 4 hamming bits 118
|
||||||
|
//
|
||||||
|
// 11 voice bits 122
|
||||||
|
// 4 hamming bits 133
|
||||||
|
//
|
||||||
|
// 7 voice bits 137
|
||||||
|
|
||||||
|
// Process the c0 section first to allow the de-whitening to be accurate
|
||||||
|
|
||||||
|
// Check/Fix FEC
|
||||||
|
bool* bit = temp;
|
||||||
|
|
||||||
|
// c0
|
||||||
|
unsigned int g1 = 0U;
|
||||||
|
for (unsigned int i = 0U; i < 23U; i++)
|
||||||
|
g1 = (g1 << 1) | (bit[i] ? 0x01U : 0x00U);
|
||||||
|
unsigned int c0data = CGolay24128::decode23127(g1);
|
||||||
|
unsigned int g2 = CGolay24128::encode23127(c0data);
|
||||||
|
for (int i = 23; i >= 0; i--) {
|
||||||
|
bit[i] = (g2 & 0x01U) == 0x01U;
|
||||||
|
g2 >>= 1;
|
||||||
|
}
|
||||||
|
bit += 23U;
|
||||||
|
|
||||||
|
bool prn[114U];
|
||||||
|
|
||||||
|
// Create the whitening vector and save it for future use
|
||||||
|
unsigned int p = 16U * c0data;
|
||||||
|
for (unsigned int i = 0U; i < 114U; i++) {
|
||||||
|
p = (173U * p + 13849U) % 65536U;
|
||||||
|
prn[i] = p >= 32768U;
|
||||||
|
}
|
||||||
|
|
||||||
|
// De-whiten some bits
|
||||||
|
for (unsigned int i = 0U; i < 114U; i++)
|
||||||
|
temp[i + 23U] ^= prn[i];
|
||||||
|
|
||||||
|
// c1
|
||||||
|
g1 = 0U;
|
||||||
|
for (unsigned int i = 0U; i < 23U; i++)
|
||||||
|
g1 = (g1 << 1) | (bit[i] ? 0x01U : 0x00U);
|
||||||
|
unsigned int c1data = CGolay24128::decode23127(g1);
|
||||||
|
g2 = CGolay24128::encode23127(c1data);
|
||||||
|
for (int i = 23; i >= 0; i--) {
|
||||||
|
bit[i] = (g2 & 0x01U) == 0x01U;
|
||||||
|
g2 >>= 1;
|
||||||
|
}
|
||||||
|
bit += 23U;
|
||||||
|
|
||||||
|
// c2
|
||||||
|
g1 = 0;
|
||||||
|
for (unsigned int i = 0U; i < 23U; i++)
|
||||||
|
g1 = (g1 << 1) | (bit[i] ? 0x01U : 0x00U);
|
||||||
|
unsigned int c2data = CGolay24128::decode23127(g1);
|
||||||
|
g2 = CGolay24128::encode23127(c2data);
|
||||||
|
for (int i = 23; i >= 0; i--) {
|
||||||
|
bit[i] = (g2 & 0x01U) == 0x01U;
|
||||||
|
g2 >>= 1;
|
||||||
|
}
|
||||||
|
bit += 23U;
|
||||||
|
|
||||||
|
// c3
|
||||||
|
g1 = 0U;
|
||||||
|
for (unsigned int i = 0U; i < 23U; i++)
|
||||||
|
g1 = (g1 << 1) | (bit[i] ? 0x01U : 0x00U);
|
||||||
|
unsigned int c3data = CGolay24128::decode23127(g1);
|
||||||
|
g2 = CGolay24128::encode23127(c3data);
|
||||||
|
for (int i = 23; i >= 0; i--) {
|
||||||
|
bit[i] = (g2 & 0x01U) == 0x01U;
|
||||||
|
g2 >>= 1;
|
||||||
|
}
|
||||||
|
bit += 23U;
|
||||||
|
|
||||||
|
// c4
|
||||||
|
CHamming::decode15113_1(bit);
|
||||||
|
bit += 15U;
|
||||||
|
|
||||||
|
// c5
|
||||||
|
CHamming::decode15113_1(bit);
|
||||||
|
bit += 15U;
|
||||||
|
|
||||||
|
// c6
|
||||||
|
CHamming::decode15113_1(bit);
|
||||||
|
|
||||||
|
// Whiten some bits
|
||||||
|
for (unsigned int i = 0U; i < 114U; i++)
|
||||||
|
temp[i + 23U] ^= prn[i];
|
||||||
|
|
||||||
|
unsigned int errors = 0U;
|
||||||
|
for (unsigned int i = 0U; i < 144U; i++) {
|
||||||
|
if (orig[i] != temp[i])
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interleave
|
||||||
|
for (unsigned int i = 0U; i < 144U; i++) {
|
||||||
|
unsigned int n = IMBE_INTERLEAVE[i];
|
||||||
|
WRITE_BIT(bytes, n, temp[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CAMBEFEC::regenerateDStar(unsigned int& a, unsigned int& b) const
|
||||||
|
{
|
||||||
|
unsigned int orig_a = a;
|
||||||
|
unsigned int orig_b = b;
|
||||||
|
|
||||||
unsigned int data = CGolay24128::decode24128(a);
|
unsigned int data = CGolay24128::decode24128(a);
|
||||||
|
|
||||||
unsigned int new_a = CGolay24128::encode24128(data);
|
a = CGolay24128::encode24128(data);
|
||||||
|
|
||||||
// The PRNG
|
// The PRNG
|
||||||
unsigned int p = PRNG_TABLE[data];
|
unsigned int p = PRNG_TABLE[data];
|
||||||
|
@ -617,21 +806,66 @@ unsigned int CAMBEFEC::regenerate(unsigned int& a, unsigned int& b, unsigned int
|
||||||
|
|
||||||
unsigned int datb = CGolay24128::decode24128(b);
|
unsigned int datb = CGolay24128::decode24128(b);
|
||||||
|
|
||||||
unsigned int new_b = CGolay24128::encode24128(datb);
|
b = CGolay24128::encode24128(datb);
|
||||||
|
|
||||||
new_b ^= p;
|
b ^= p;
|
||||||
|
|
||||||
unsigned int errors = 0U;
|
unsigned int errsA = 0U, errsB = 0U;
|
||||||
unsigned int mask = 0x01;
|
|
||||||
for (unsigned int i = 0U; i < 24U; i++, mask <<= 1) {
|
unsigned int v = a ^ orig_a;
|
||||||
if ((old_a & mask) != (new_a & mask))
|
while (v != 0U) {
|
||||||
errors++;
|
v &= v - 1U;
|
||||||
if ((old_b & mask) != (new_b & mask))
|
errsA++;
|
||||||
errors++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
a = new_a;
|
v = b ^ orig_b;
|
||||||
b = new_b;
|
while (v != 0U) {
|
||||||
|
v &= v - 1U;
|
||||||
return errors;
|
errsB++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return errsA + errsB;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CAMBEFEC::regenerateDMR(unsigned int& a, unsigned int& b, unsigned int& c) const
|
||||||
|
{
|
||||||
|
unsigned int orig_a = a;
|
||||||
|
unsigned int orig_b = b;
|
||||||
|
|
||||||
|
unsigned int data = CGolay24128::decode24128(a);
|
||||||
|
|
||||||
|
a = CGolay24128::encode24128(data);
|
||||||
|
|
||||||
|
// The PRNG
|
||||||
|
unsigned int p = PRNG_TABLE[data] >> 1;
|
||||||
|
|
||||||
|
b ^= p;
|
||||||
|
|
||||||
|
unsigned int datb = CGolay24128::decode23127(b);
|
||||||
|
|
||||||
|
b = CGolay24128::encode23127(datb) >> 1;
|
||||||
|
|
||||||
|
b ^= p;
|
||||||
|
|
||||||
|
unsigned int errsA = 0U, errsB = 0U;
|
||||||
|
|
||||||
|
unsigned int v = a ^ orig_a;
|
||||||
|
while (v != 0U) {
|
||||||
|
v &= v - 1U;
|
||||||
|
errsA++;
|
||||||
|
}
|
||||||
|
|
||||||
|
v = b ^ orig_b;
|
||||||
|
while (v != 0U) {
|
||||||
|
v &= v - 1U;
|
||||||
|
errsB++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errsA >= 4U || ((errsA + errsB) >= 6U && errsA >= 2U)) {
|
||||||
|
a = 0xF00292U;
|
||||||
|
b = 0x0E0B20U;
|
||||||
|
c = 0x000000U;
|
||||||
|
}
|
||||||
|
|
||||||
|
return errsA + errsB;
|
||||||
}
|
}
|
||||||
|
|
14
AMBEFEC.h
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2010,2014,2016 by Jonathan Naylor G4KLX
|
* Copyright (C) 2010,2014,2016,2018 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,21 +16,25 @@
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef AMBEFEC_H
|
#if !defined(AMBEFEC_H)
|
||||||
#define AMBEFEC_H
|
#define AMBEFEC_H
|
||||||
|
|
||||||
#include "Golay24128.h"
|
|
||||||
|
|
||||||
class CAMBEFEC {
|
class CAMBEFEC {
|
||||||
public:
|
public:
|
||||||
CAMBEFEC();
|
CAMBEFEC();
|
||||||
~CAMBEFEC();
|
~CAMBEFEC();
|
||||||
|
|
||||||
unsigned int regenerateDMR(unsigned char* bytes) const;
|
unsigned int regenerateDMR(unsigned char* bytes) const;
|
||||||
|
|
||||||
unsigned int regenerateDStar(unsigned char* bytes) const;
|
unsigned int regenerateDStar(unsigned char* bytes) const;
|
||||||
|
|
||||||
|
unsigned int regenerateYSFDN(unsigned char* bytes) const;
|
||||||
|
|
||||||
|
unsigned int regenerateIMBE(unsigned char* bytes) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned int regenerate(unsigned int& a, unsigned int& b, unsigned int& c) const;
|
unsigned int regenerateDStar(unsigned int& a, unsigned int& b) const;
|
||||||
|
unsigned int regenerateDMR(unsigned int& a, unsigned int& b,unsigned int& c) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
139
BCH.cpp
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
/*
|
||||||
|
* File: bch3.c
|
||||||
|
* Title: Encoder/decoder for binary BCH codes in C (Version 3.1)
|
||||||
|
* Author: Robert Morelos-Zaragoza
|
||||||
|
* Date: August 1994
|
||||||
|
* Revised: June 13, 1997
|
||||||
|
*
|
||||||
|
* =============== Encoder/Decoder for binary BCH codes in C =================
|
||||||
|
*
|
||||||
|
* Version 1: Original program. The user provides the generator polynomial
|
||||||
|
* of the code (cumbersome!).
|
||||||
|
* Version 2: Computes the generator polynomial of the code.
|
||||||
|
* Version 3: No need to input the coefficients of a primitive polynomial of
|
||||||
|
* degree m, used to construct the Galois Field GF(2**m). The
|
||||||
|
* program now works for any binary BCH code of length such that:
|
||||||
|
* 2**(m-1) - 1 < length <= 2**m - 1
|
||||||
|
*
|
||||||
|
* Note: You may have to change the size of the arrays to make it work.
|
||||||
|
*
|
||||||
|
* The encoding and decoding methods used in this program are based on the
|
||||||
|
* book "Error Control Coding: Fundamentals and Applications", by Lin and
|
||||||
|
* Costello, Prentice Hall, 1983.
|
||||||
|
*
|
||||||
|
* Thanks to Patrick Boyle (pboyle@era.com) for his observation that 'bch2.c'
|
||||||
|
* did not work for lengths other than 2**m-1 which led to this new version.
|
||||||
|
* Portions of this program are from 'rs.c', a Reed-Solomon encoder/decoder
|
||||||
|
* in C, written by Simon Rockliff (simon@augean.ua.oz.au) on 21/9/89. The
|
||||||
|
* previous version of the BCH encoder/decoder in C, 'bch2.c', was written by
|
||||||
|
* Robert Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) on 5/19/92.
|
||||||
|
*
|
||||||
|
* NOTE:
|
||||||
|
* The author is not responsible for any malfunctioning of
|
||||||
|
* this program, nor for any damage caused by it. Please include the
|
||||||
|
* original program along with these comments in any redistribution.
|
||||||
|
*
|
||||||
|
* For more information, suggestions, or other ideas on implementing error
|
||||||
|
* correcting codes, please contact me at:
|
||||||
|
*
|
||||||
|
* Robert Morelos-Zaragoza
|
||||||
|
* 5120 Woodway, Suite 7036
|
||||||
|
* Houston, Texas 77056
|
||||||
|
*
|
||||||
|
* email: r.morelos-zaragoza@ieee.org
|
||||||
|
*
|
||||||
|
* COPYRIGHT NOTICE: This computer program is free for non-commercial purposes.
|
||||||
|
* You may implement this program for any non-commercial application. You may
|
||||||
|
* also implement this program for commercial purposes, provided that you
|
||||||
|
* obtain my written permission. Any modification of this program is covered
|
||||||
|
* by this copyright.
|
||||||
|
*
|
||||||
|
* == Copyright (c) 1994-7, Robert Morelos-Zaragoza. All rights reserved. ==
|
||||||
|
*
|
||||||
|
* m = order of the Galois field GF(2**m)
|
||||||
|
* n = 2**m - 1 = size of the multiplicative group of GF(2**m)
|
||||||
|
* length = length of the BCH code
|
||||||
|
* t = error correcting capability (max. no. of errors the code corrects)
|
||||||
|
* d = 2*t + 1 = designed min. distance = no. of consecutive roots of g(x) + 1
|
||||||
|
* k = n - deg(g(x)) = dimension (no. of information bits/codeword) of the code
|
||||||
|
* p[] = coefficients of a primitive polynomial used to generate GF(2**m)
|
||||||
|
* g[] = coefficients of the generator polynomial, g(x)
|
||||||
|
* alpha_to [] = log table of GF(2**m)
|
||||||
|
* index_of[] = antilog table of GF(2**m)
|
||||||
|
* data[] = information bits = coefficients of data polynomial, i(x)
|
||||||
|
* bb[] = coefficients of redundancy polynomial x^(length-k) i(x) modulo g(x)
|
||||||
|
* numerr = number of errors
|
||||||
|
* errpos[] = error positions
|
||||||
|
* recd[] = coefficients of the received polynomial
|
||||||
|
* decerror = number of decoding errors (in _message_ positions)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "BCH.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U };
|
||||||
|
|
||||||
|
#define WRITE_BIT(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7])
|
||||||
|
#define READ_BIT(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
|
||||||
|
|
||||||
|
const int length = 63;
|
||||||
|
const int k = 16;
|
||||||
|
|
||||||
|
const int g[] = {1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1,
|
||||||
|
1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1};
|
||||||
|
|
||||||
|
CBCH::CBCH()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CBCH::~CBCH()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CBCH::encode(const int* data, int* bb)
|
||||||
|
/*
|
||||||
|
* Compute redundacy bb[], the coefficients of b(x). The redundancy
|
||||||
|
* polynomial b(x) is the remainder after dividing x^(length-k)*data(x)
|
||||||
|
* by the generator polynomial g(x).
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
for (int i = 0; i < length - k; i++)
|
||||||
|
bb[i] = 0;
|
||||||
|
|
||||||
|
for (int i = k - 1; i >= 0; i--) {
|
||||||
|
int feedback = data[i] ^ bb[length - k - 1];
|
||||||
|
if (feedback != 0) {
|
||||||
|
for (int j = length - k - 1; j > 0; j--)
|
||||||
|
if (g[j] != 0)
|
||||||
|
bb[j] = bb[j - 1] ^ feedback;
|
||||||
|
else
|
||||||
|
bb[j] = bb[j - 1];
|
||||||
|
bb[0] = g[0] && feedback;
|
||||||
|
} else {
|
||||||
|
for (int j = length - k - 1; j > 0; j--)
|
||||||
|
bb[j] = bb[j - 1];
|
||||||
|
bb[0] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CBCH::encode(unsigned char* nid)
|
||||||
|
{
|
||||||
|
assert(nid != NULL);
|
||||||
|
|
||||||
|
int data[16];
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
data[i] = READ_BIT(nid, i) ? 1 : 0;
|
||||||
|
|
||||||
|
int bb[63];
|
||||||
|
encode(data, bb);
|
||||||
|
|
||||||
|
for (int i = 0; i < (length - k); i++) {
|
||||||
|
bool b = bb[i] == 1;
|
||||||
|
WRITE_BIT(nid, i + 16U, b);
|
||||||
|
}
|
||||||
|
}
|
33
BCH.h
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(BCH_H)
|
||||||
|
#define BCH_H
|
||||||
|
|
||||||
|
class CBCH {
|
||||||
|
public:
|
||||||
|
CBCH();
|
||||||
|
~CBCH();
|
||||||
|
|
||||||
|
void encode(unsigned char* data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void encode(const int* data, int* bb);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -162,7 +162,7 @@ void CBPTC19696::decodeErrorCheck()
|
||||||
// Run through each of the 9 rows containing data
|
// Run through each of the 9 rows containing data
|
||||||
for (unsigned int r = 0U; r < 9U; r++) {
|
for (unsigned int r = 0U; r < 9U; r++) {
|
||||||
unsigned int pos = (r * 15U) + 1U;
|
unsigned int pos = (r * 15U) + 1U;
|
||||||
if (CHamming::decode15113(m_deInterData + pos))
|
if (CHamming::decode15113_2(m_deInterData + pos))
|
||||||
fixing = true;
|
fixing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,6 +268,13 @@ void CBPTC19696::encodeExtractData(const unsigned char* in) const
|
||||||
// Check each row with a Hamming (15,11,3) code and each column with a Hamming (13,9,3) code
|
// Check each row with a Hamming (15,11,3) code and each column with a Hamming (13,9,3) code
|
||||||
void CBPTC19696::encodeErrorCheck()
|
void CBPTC19696::encodeErrorCheck()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// Run through each of the 9 rows containing data
|
||||||
|
for (unsigned int r = 0U; r < 9U; r++) {
|
||||||
|
unsigned int pos = (r * 15U) + 1U;
|
||||||
|
CHamming::encode15113_2(m_deInterData + pos);
|
||||||
|
}
|
||||||
|
|
||||||
// Run through each of the 15 columns
|
// Run through each of the 15 columns
|
||||||
bool col[13U];
|
bool col[13U];
|
||||||
for (unsigned int c = 0U; c < 15U; c++) {
|
for (unsigned int c = 0U; c < 15U; c++) {
|
||||||
|
@ -285,12 +292,6 @@ void CBPTC19696::encodeErrorCheck()
|
||||||
pos = pos + 15U;
|
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
|
// Interleave the raw data
|
||||||
|
@ -328,7 +329,7 @@ void CBPTC19696::encodeExtractBinary(unsigned char* data)
|
||||||
unsigned char byte;
|
unsigned char byte;
|
||||||
CUtils::bitsToByteBE(m_rawData + 96U, byte);
|
CUtils::bitsToByteBE(m_rawData + 96U, byte);
|
||||||
data[12U] = (data[12U] & 0x3FU) | ((byte >> 0) & 0xC0U);
|
data[12U] = (data[12U] & 0x3FU) | ((byte >> 0) & 0xC0U);
|
||||||
data[13U] = (data[13U] & 0xFCU) | ((byte >> 4) & 0x03U);
|
data[20U] = (data[20U] & 0xFCU) | ((byte >> 4) & 0x03U);
|
||||||
|
|
||||||
// Second block
|
// Second block
|
||||||
CUtils::bitsToByteBE(m_rawData + 100U, data[21U]);
|
CUtils::bitsToByteBE(m_rawData + 100U, data[21U]);
|
||||||
|
|
153
CASTInfo.cpp
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016,2018,2020 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 "CASTInfo.h"
|
||||||
|
|
||||||
|
static bool networkInfoInitialized = false;
|
||||||
|
static unsigned char passCounter = 0;
|
||||||
|
|
||||||
|
CCASTInfo::CCASTInfo(CModem* modem) :
|
||||||
|
CDisplay(),
|
||||||
|
m_modem(modem),
|
||||||
|
m_ipaddress()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CCASTInfo::~CCASTInfo()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CCASTInfo::open()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCASTInfo::setIdleInt()
|
||||||
|
{
|
||||||
|
unsigned char info[100U];
|
||||||
|
CNetworkInfo* m_network;
|
||||||
|
|
||||||
|
passCounter ++;
|
||||||
|
if (passCounter > 253U)
|
||||||
|
networkInfoInitialized = false;
|
||||||
|
|
||||||
|
if (! networkInfoInitialized) {
|
||||||
|
//LogMessage("Initialize CNetworkInfo");
|
||||||
|
info[0]=0;
|
||||||
|
m_network = new CNetworkInfo;
|
||||||
|
m_network->getNetworkInterface(info);
|
||||||
|
m_ipaddress = (char*)info;
|
||||||
|
delete m_network;
|
||||||
|
|
||||||
|
if (m_modem != NULL)
|
||||||
|
m_modem->writeIPInfo(m_ipaddress);
|
||||||
|
|
||||||
|
networkInfoInitialized = true;
|
||||||
|
passCounter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCASTInfo::setErrorInt(const char* text)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCASTInfo::setLockoutInt()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCASTInfo::setQuitInt()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCASTInfo::setFMInt()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCASTInfo::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector)
|
||||||
|
{
|
||||||
|
if (m_modem != NULL)
|
||||||
|
m_modem->writeDStarInfo(my1, my2, your, type, reflector);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCASTInfo::clearDStarInt()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCASTInfo::writeDMRInt(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type)
|
||||||
|
{
|
||||||
|
if (m_modem != NULL)
|
||||||
|
m_modem->writeDMRInfo(slotNo, src, group, dst, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCASTInfo::clearDMRInt(unsigned int slotNo)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCASTInfo::writeFusionInt(const char* source, const char* dest, const char* type, const char* origin)
|
||||||
|
{
|
||||||
|
if (m_modem != NULL)
|
||||||
|
m_modem->writeYSFInfo(source, dest, type, origin);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCASTInfo::clearFusionInt()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCASTInfo::writeP25Int(const char* source, bool group, unsigned int dest, const char* type)
|
||||||
|
{
|
||||||
|
if (m_modem != NULL)
|
||||||
|
m_modem->writeP25Info(source, group, dest, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCASTInfo::clearP25Int()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCASTInfo::writeNXDNInt(const char* source, bool group, unsigned int dest, const char* type)
|
||||||
|
{
|
||||||
|
if (m_modem != NULL)
|
||||||
|
m_modem->writeNXDNInfo(source, group, dest, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCASTInfo::clearNXDNInt()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCASTInfo::writePOCSAGInt(uint32_t ric, const std::string& message)
|
||||||
|
{
|
||||||
|
if (m_modem != NULL)
|
||||||
|
m_modem->writePOCSAGInfo(ric, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCASTInfo::clearPOCSAGInt()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCASTInfo::writeCWInt()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCASTInfo::clearCWInt()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCASTInfo::close()
|
||||||
|
{
|
||||||
|
}
|
71
CASTInfo.h
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016,2018,2020 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(CASTINFO_H)
|
||||||
|
#define CASTINFO_H
|
||||||
|
|
||||||
|
#include "Display.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "NetworkInfo.h"
|
||||||
|
#include "Modem.h"
|
||||||
|
class CCASTInfo : public CDisplay
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CCASTInfo(CModem* modem);
|
||||||
|
virtual ~CCASTInfo();
|
||||||
|
|
||||||
|
virtual bool open();
|
||||||
|
|
||||||
|
virtual void close();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void setIdleInt();
|
||||||
|
virtual void setErrorInt(const char* text);
|
||||||
|
virtual void setLockoutInt();
|
||||||
|
virtual void setQuitInt();
|
||||||
|
virtual void setFMInt();
|
||||||
|
|
||||||
|
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
|
||||||
|
virtual void clearDStarInt();
|
||||||
|
|
||||||
|
virtual void writeDMRInt(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type);
|
||||||
|
virtual void clearDMRInt(unsigned int slotNo);
|
||||||
|
|
||||||
|
virtual void writeFusionInt(const char* source, const char* dest, const char* type, const char* origin);
|
||||||
|
virtual void clearFusionInt();
|
||||||
|
|
||||||
|
virtual void writeP25Int(const char* source, bool group, unsigned int dest, const char* type);
|
||||||
|
virtual void clearP25Int();
|
||||||
|
|
||||||
|
virtual void writeNXDNInt(const char* source, bool group, unsigned int dest, const char* type);
|
||||||
|
virtual void clearNXDNInt();
|
||||||
|
|
||||||
|
virtual void writePOCSAGInt(uint32_t ric, const std::string& message);
|
||||||
|
virtual void clearPOCSAGInt();
|
||||||
|
|
||||||
|
virtual void writeCWInt();
|
||||||
|
virtual void clearCWInt();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CModem* m_modem;
|
||||||
|
std::string m_ipaddress;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
210
CRC.cpp
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -19,11 +19,106 @@
|
||||||
#include "CRC.h"
|
#include "CRC.h"
|
||||||
|
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
const uint8_t CRC8_TABLE[] = {
|
||||||
|
0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31,
|
||||||
|
0x24, 0x23, 0x2A, 0x2D, 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
|
||||||
|
0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, 0xE0, 0xE7, 0xEE, 0xE9,
|
||||||
|
0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
|
||||||
|
0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1,
|
||||||
|
0xB4, 0xB3, 0xBA, 0xBD, 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
|
||||||
|
0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, 0xB7, 0xB0, 0xB9, 0xBE,
|
||||||
|
0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
|
||||||
|
0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16,
|
||||||
|
0x03, 0x04, 0x0D, 0x0A, 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
|
||||||
|
0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, 0x89, 0x8E, 0x87, 0x80,
|
||||||
|
0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
|
||||||
|
0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8,
|
||||||
|
0xDD, 0xDA, 0xD3, 0xD4, 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
|
||||||
|
0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, 0x19, 0x1E, 0x17, 0x10,
|
||||||
|
0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
|
||||||
|
0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F,
|
||||||
|
0x6A, 0x6D, 0x64, 0x63, 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
|
||||||
|
0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, 0xAE, 0xA9, 0xA0, 0xA7,
|
||||||
|
0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
|
||||||
|
0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF,
|
||||||
|
0xFA, 0xFD, 0xF4, 0xF3, 0x01 };
|
||||||
|
|
||||||
|
const uint16_t CCITT16_TABLE1[] = {
|
||||||
|
0x0000U, 0x1189U, 0x2312U, 0x329bU, 0x4624U, 0x57adU, 0x6536U, 0x74bfU,
|
||||||
|
0x8c48U, 0x9dc1U, 0xaf5aU, 0xbed3U, 0xca6cU, 0xdbe5U, 0xe97eU, 0xf8f7U,
|
||||||
|
0x1081U, 0x0108U, 0x3393U, 0x221aU, 0x56a5U, 0x472cU, 0x75b7U, 0x643eU,
|
||||||
|
0x9cc9U, 0x8d40U, 0xbfdbU, 0xae52U, 0xdaedU, 0xcb64U, 0xf9ffU, 0xe876U,
|
||||||
|
0x2102U, 0x308bU, 0x0210U, 0x1399U, 0x6726U, 0x76afU, 0x4434U, 0x55bdU,
|
||||||
|
0xad4aU, 0xbcc3U, 0x8e58U, 0x9fd1U, 0xeb6eU, 0xfae7U, 0xc87cU, 0xd9f5U,
|
||||||
|
0x3183U, 0x200aU, 0x1291U, 0x0318U, 0x77a7U, 0x662eU, 0x54b5U, 0x453cU,
|
||||||
|
0xbdcbU, 0xac42U, 0x9ed9U, 0x8f50U, 0xfbefU, 0xea66U, 0xd8fdU, 0xc974U,
|
||||||
|
0x4204U, 0x538dU, 0x6116U, 0x709fU, 0x0420U, 0x15a9U, 0x2732U, 0x36bbU,
|
||||||
|
0xce4cU, 0xdfc5U, 0xed5eU, 0xfcd7U, 0x8868U, 0x99e1U, 0xab7aU, 0xbaf3U,
|
||||||
|
0x5285U, 0x430cU, 0x7197U, 0x601eU, 0x14a1U, 0x0528U, 0x37b3U, 0x263aU,
|
||||||
|
0xdecdU, 0xcf44U, 0xfddfU, 0xec56U, 0x98e9U, 0x8960U, 0xbbfbU, 0xaa72U,
|
||||||
|
0x6306U, 0x728fU, 0x4014U, 0x519dU, 0x2522U, 0x34abU, 0x0630U, 0x17b9U,
|
||||||
|
0xef4eU, 0xfec7U, 0xcc5cU, 0xddd5U, 0xa96aU, 0xb8e3U, 0x8a78U, 0x9bf1U,
|
||||||
|
0x7387U, 0x620eU, 0x5095U, 0x411cU, 0x35a3U, 0x242aU, 0x16b1U, 0x0738U,
|
||||||
|
0xffcfU, 0xee46U, 0xdcddU, 0xcd54U, 0xb9ebU, 0xa862U, 0x9af9U, 0x8b70U,
|
||||||
|
0x8408U, 0x9581U, 0xa71aU, 0xb693U, 0xc22cU, 0xd3a5U, 0xe13eU, 0xf0b7U,
|
||||||
|
0x0840U, 0x19c9U, 0x2b52U, 0x3adbU, 0x4e64U, 0x5fedU, 0x6d76U, 0x7cffU,
|
||||||
|
0x9489U, 0x8500U, 0xb79bU, 0xa612U, 0xd2adU, 0xc324U, 0xf1bfU, 0xe036U,
|
||||||
|
0x18c1U, 0x0948U, 0x3bd3U, 0x2a5aU, 0x5ee5U, 0x4f6cU, 0x7df7U, 0x6c7eU,
|
||||||
|
0xa50aU, 0xb483U, 0x8618U, 0x9791U, 0xe32eU, 0xf2a7U, 0xc03cU, 0xd1b5U,
|
||||||
|
0x2942U, 0x38cbU, 0x0a50U, 0x1bd9U, 0x6f66U, 0x7eefU, 0x4c74U, 0x5dfdU,
|
||||||
|
0xb58bU, 0xa402U, 0x9699U, 0x8710U, 0xf3afU, 0xe226U, 0xd0bdU, 0xc134U,
|
||||||
|
0x39c3U, 0x284aU, 0x1ad1U, 0x0b58U, 0x7fe7U, 0x6e6eU, 0x5cf5U, 0x4d7cU,
|
||||||
|
0xc60cU, 0xd785U, 0xe51eU, 0xf497U, 0x8028U, 0x91a1U, 0xa33aU, 0xb2b3U,
|
||||||
|
0x4a44U, 0x5bcdU, 0x6956U, 0x78dfU, 0x0c60U, 0x1de9U, 0x2f72U, 0x3efbU,
|
||||||
|
0xd68dU, 0xc704U, 0xf59fU, 0xe416U, 0x90a9U, 0x8120U, 0xb3bbU, 0xa232U,
|
||||||
|
0x5ac5U, 0x4b4cU, 0x79d7U, 0x685eU, 0x1ce1U, 0x0d68U, 0x3ff3U, 0x2e7aU,
|
||||||
|
0xe70eU, 0xf687U, 0xc41cU, 0xd595U, 0xa12aU, 0xb0a3U, 0x8238U, 0x93b1U,
|
||||||
|
0x6b46U, 0x7acfU, 0x4854U, 0x59ddU, 0x2d62U, 0x3cebU, 0x0e70U, 0x1ff9U,
|
||||||
|
0xf78fU, 0xe606U, 0xd49dU, 0xc514U, 0xb1abU, 0xa022U, 0x92b9U, 0x8330U,
|
||||||
|
0x7bc7U, 0x6a4eU, 0x58d5U, 0x495cU, 0x3de3U, 0x2c6aU, 0x1ef1U, 0x0f78U };
|
||||||
|
|
||||||
|
const uint16_t CCITT16_TABLE2[] = {
|
||||||
|
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
|
||||||
|
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
|
||||||
|
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
|
||||||
|
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
|
||||||
|
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
|
||||||
|
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
|
||||||
|
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
|
||||||
|
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
|
||||||
|
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
|
||||||
|
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
|
||||||
|
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
|
||||||
|
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
|
||||||
|
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
|
||||||
|
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
|
||||||
|
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
|
||||||
|
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
|
||||||
|
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
|
||||||
|
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||||
|
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
|
||||||
|
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
|
||||||
|
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
|
||||||
|
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
|
||||||
|
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
|
||||||
|
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
|
||||||
|
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
|
||||||
|
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
|
||||||
|
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
|
||||||
|
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
|
||||||
|
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
|
||||||
|
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
|
||||||
|
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
|
||||||
|
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 };
|
||||||
|
|
||||||
|
|
||||||
bool CCRC::checkFiveBit(bool* in, unsigned int tcrc)
|
bool CCRC::checkFiveBit(bool* in, unsigned int tcrc)
|
||||||
{
|
{
|
||||||
assert(in != NULL);
|
assert(in != NULL);
|
||||||
|
@ -50,65 +145,96 @@ void CCRC::encodeFiveBit(const bool* in, unsigned int& tcrc)
|
||||||
tcrc = total;
|
tcrc = total;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char CCRC::encodeEightBit(const unsigned char *in, unsigned int length)
|
void CCRC::addCCITT162(unsigned char *in, unsigned int length)
|
||||||
{
|
{
|
||||||
assert(in != NULL);
|
assert(in != NULL);
|
||||||
|
assert(length > 2U);
|
||||||
|
|
||||||
unsigned char crc = 0x00U;
|
union {
|
||||||
|
uint16_t crc16;
|
||||||
|
uint8_t crc8[2U];
|
||||||
|
};
|
||||||
|
|
||||||
for (unsigned int i = 0U; i < length; i++) {
|
crc16 = 0U;
|
||||||
crc ^= in[i];
|
|
||||||
|
|
||||||
for (unsigned int j = 0U; j < 8U; j++) {
|
for (unsigned i = 0U; i < (length - 2U); i++)
|
||||||
if ((crc & 0x80U) == 0x80U) {
|
crc16 = (uint16_t(crc8[0U]) << 8) ^ CCITT16_TABLE2[crc8[1U] ^ in[i]];
|
||||||
crc <<= 1;
|
|
||||||
crc ^= 0x07U;
|
crc16 = ~crc16;
|
||||||
} else {
|
|
||||||
crc <<= 1;
|
in[length - 1U] = crc8[0U];
|
||||||
}
|
in[length - 2U] = crc8[1U];
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return crc;
|
bool CCRC::checkCCITT162(const unsigned char *in, unsigned int length)
|
||||||
}
|
|
||||||
|
|
||||||
bool CCRC::checkCSBK(const unsigned char *in)
|
|
||||||
{
|
{
|
||||||
unsigned short crc16 = 0U;
|
assert(in != NULL);
|
||||||
|
assert(length > 2U);
|
||||||
|
|
||||||
// Run through all 12 bits
|
union {
|
||||||
for (unsigned int a = 0; a < 12U; a++) {
|
uint16_t crc16;
|
||||||
unsigned char val = in[a];
|
uint8_t crc8[2U];
|
||||||
|
};
|
||||||
|
|
||||||
// Allow for the CSBK CRC mask
|
crc16 = 0U;
|
||||||
if (a > 9U)
|
|
||||||
val ^= 0xA5U;
|
|
||||||
|
|
||||||
for (unsigned int i = 0U; i < 8U; i++) {
|
for (unsigned i = 0U; i < (length - 2U); i++)
|
||||||
bool c15 = (crc16 >> 15 & 0x01U) == 0x01U;
|
crc16 = (uint16_t(crc8[0U]) << 8) ^ CCITT16_TABLE2[crc8[1U] ^ in[i]];
|
||||||
bool bit = (val >> (7 - i) & 0x01U) == 0x01U;
|
|
||||||
crc16 <<= 1;
|
crc16 = ~crc16;
|
||||||
if (c15 ^ bit)
|
|
||||||
crc16 ^= 0x1021U;
|
return crc8[0U] == in[length - 1U] && crc8[1U] == in[length - 2U];
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return crc16 == 0x1D0FU;
|
void CCRC::addCCITT161(unsigned char *in, unsigned int length)
|
||||||
|
{
|
||||||
|
assert(in != NULL);
|
||||||
|
assert(length > 2U);
|
||||||
|
|
||||||
|
union {
|
||||||
|
uint16_t crc16;
|
||||||
|
uint8_t crc8[2U];
|
||||||
|
};
|
||||||
|
|
||||||
|
crc16 = 0xFFFFU;
|
||||||
|
|
||||||
|
for (unsigned int i = 0U; i < (length - 2U); i++)
|
||||||
|
crc16 = uint16_t(crc8[1U]) ^ CCITT16_TABLE1[crc8[0U] ^ in[i]];
|
||||||
|
|
||||||
|
crc16 = ~crc16;
|
||||||
|
|
||||||
|
in[length - 2U] = crc8[0U];
|
||||||
|
in[length - 1U] = crc8[1U];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CCRC::checkCCITT161(const unsigned char *in, unsigned int length)
|
||||||
|
{
|
||||||
|
assert(in != NULL);
|
||||||
|
assert(length > 2U);
|
||||||
|
|
||||||
|
union {
|
||||||
|
uint16_t crc16;
|
||||||
|
uint8_t crc8[2U];
|
||||||
|
};
|
||||||
|
|
||||||
|
crc16 = 0xFFFFU;
|
||||||
|
|
||||||
|
for (unsigned int i = 0U; i < (length - 2U); i++)
|
||||||
|
crc16 = uint16_t(crc8[1U]) ^ CCITT16_TABLE1[crc8[0U] ^ in[i]];
|
||||||
|
|
||||||
|
crc16 = ~crc16;
|
||||||
|
|
||||||
|
return crc8[0U] == in[length - 2U] && crc8[1U] == in[length - 1U];
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char CCRC::crc8(const unsigned char *in, unsigned int length)
|
unsigned char CCRC::crc8(const unsigned char *in, unsigned int length)
|
||||||
{
|
{
|
||||||
unsigned int crc = 0U;
|
assert(in != NULL);
|
||||||
|
|
||||||
for (unsigned int j = 0U; j < length; j++, in++) {
|
uint8_t crc = 0U;
|
||||||
crc ^= (*in << 8);
|
|
||||||
|
|
||||||
for (unsigned int i = 0U; i < 8U; i++) {
|
for (unsigned int i = 0U; i < length; i++)
|
||||||
if (crc & 0x8000U)
|
crc = CRC8_TABLE[crc ^ in[i]];
|
||||||
crc ^= (0x1070U << 3);
|
|
||||||
crc <<= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return crc >> 8;
|
return crc;
|
||||||
}
|
}
|
||||||
|
|
8
CRC.h
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -25,9 +25,11 @@ public:
|
||||||
static bool checkFiveBit(bool* in, unsigned int tcrc);
|
static bool checkFiveBit(bool* in, unsigned int tcrc);
|
||||||
static void encodeFiveBit(const bool* in, unsigned int& tcrc);
|
static void encodeFiveBit(const bool* in, unsigned int& tcrc);
|
||||||
|
|
||||||
static bool checkCSBK(const unsigned char* in);
|
static void addCCITT161(unsigned char* in, unsigned int length);
|
||||||
|
static void addCCITT162(unsigned char* in, unsigned int length);
|
||||||
|
|
||||||
static unsigned char encodeEightBit(const unsigned char* in, unsigned int length);
|
static bool checkCCITT161(const unsigned char* in, unsigned int length);
|
||||||
|
static bool checkCCITT162(const unsigned char* in, unsigned int length);
|
||||||
|
|
||||||
static unsigned char crc8(const unsigned char* in, unsigned int length);
|
static unsigned char crc8(const unsigned char* in, unsigned int length);
|
||||||
};
|
};
|
||||||
|
|
84
CSBK.cpp
|
@ -1,84 +0,0 @@
|
||||||
/*
|
|
||||||
* 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;
|
|
||||||
}
|
|
458
Conf.h
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015-2020 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -20,6 +20,7 @@
|
||||||
#define CONF_H
|
#define CONF_H
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class CConf
|
class CConf
|
||||||
{
|
{
|
||||||
|
@ -31,14 +32,15 @@ public:
|
||||||
|
|
||||||
// The General section
|
// The General section
|
||||||
std::string getCallsign() const;
|
std::string getCallsign() const;
|
||||||
|
unsigned int getId() const;
|
||||||
unsigned int getTimeout() const;
|
unsigned int getTimeout() const;
|
||||||
bool getDuplex() const;
|
bool getDuplex() const;
|
||||||
unsigned int getModeHang() const;
|
|
||||||
std::string getDisplay() const;
|
std::string getDisplay() const;
|
||||||
|
bool getDaemon() const;
|
||||||
|
|
||||||
// The Info section
|
// The Info section
|
||||||
unsigned int getRxFrequency() const;
|
unsigned int getRXFrequency() const;
|
||||||
unsigned int getTxFrequency() const;
|
unsigned int getTXFrequency() const;
|
||||||
unsigned int getPower() const;
|
unsigned int getPower() const;
|
||||||
float getLatitude() const;
|
float getLatitude() const;
|
||||||
float getLongitude() const;
|
float getLongitude() const;
|
||||||
|
@ -48,64 +50,279 @@ public:
|
||||||
std::string getURL() const;
|
std::string getURL() const;
|
||||||
|
|
||||||
// The Log section
|
// The Log section
|
||||||
std::string getLogPath() const;
|
unsigned int getLogDisplayLevel() const;
|
||||||
std::string getLogRoot() const;
|
unsigned int getLogFileLevel() const;
|
||||||
unsigned int getLogLevel() const;
|
std::string getLogFilePath() const;
|
||||||
bool getLogDisplay() const;
|
std::string getLogFileRoot() const;
|
||||||
|
|
||||||
|
// The CW ID section
|
||||||
|
bool getCWIdEnabled() const;
|
||||||
|
unsigned int getCWIdTime() const;
|
||||||
|
std::string getCWIdCallsign() const;
|
||||||
|
|
||||||
|
// The DMR Id section
|
||||||
|
std::string getDMRIdLookupFile() const;
|
||||||
|
unsigned int getDMRIdLookupTime() const;
|
||||||
|
|
||||||
|
// The NXDN Id section
|
||||||
|
std::string getNXDNIdLookupFile() const;
|
||||||
|
unsigned int getNXDNIdLookupTime() const;
|
||||||
|
|
||||||
// The Modem section
|
// The Modem section
|
||||||
std::string getModemPort() const;
|
std::string getModemPort() const;
|
||||||
|
std::string getModemProtocol() const;
|
||||||
|
unsigned int getModemAddress() const;
|
||||||
bool getModemRXInvert() const;
|
bool getModemRXInvert() const;
|
||||||
bool getModemTXInvert() const;
|
bool getModemTXInvert() const;
|
||||||
bool getModemPTTInvert() const;
|
bool getModemPTTInvert() const;
|
||||||
unsigned int getModemTXDelay() const;
|
unsigned int getModemTXDelay() const;
|
||||||
unsigned int getModemRXLevel() const;
|
unsigned int getModemDMRDelay() const;
|
||||||
unsigned int getModemTXLevel() const;
|
int getModemTXOffset() const;
|
||||||
|
int getModemRXOffset() const;
|
||||||
|
int getModemRXDCOffset() const;
|
||||||
|
int getModemTXDCOffset() const;
|
||||||
|
float getModemRFLevel() const;
|
||||||
|
float getModemRXLevel() const;
|
||||||
|
float getModemCWIdTXLevel() const;
|
||||||
|
float getModemDStarTXLevel() const;
|
||||||
|
float getModemDMRTXLevel() const;
|
||||||
|
float getModemYSFTXLevel() const;
|
||||||
|
float getModemP25TXLevel() const;
|
||||||
|
float getModemNXDNTXLevel() const;
|
||||||
|
float getModemPOCSAGTXLevel() const;
|
||||||
|
float getModemFMTXLevel() const;
|
||||||
|
std::string getModemRSSIMappingFile() const;
|
||||||
|
bool getModemTrace() const;
|
||||||
bool getModemDebug() const;
|
bool getModemDebug() const;
|
||||||
|
|
||||||
|
// The Transparent Data section
|
||||||
|
bool getTransparentEnabled() const;
|
||||||
|
std::string getTransparentRemoteAddress() const;
|
||||||
|
unsigned int getTransparentRemotePort() const;
|
||||||
|
unsigned int getTransparentLocalPort() const;
|
||||||
|
unsigned int getTransparentSendFrameType() const;
|
||||||
|
|
||||||
|
// The UMP section
|
||||||
|
bool getUMPEnabled() const;
|
||||||
|
std::string getUMPPort() const;
|
||||||
|
|
||||||
// The D-Star section
|
// The D-Star section
|
||||||
bool getDStarEnabled() const;
|
bool getDStarEnabled() const;
|
||||||
std::string getDStarModule() const;
|
std::string getDStarModule() const;
|
||||||
|
bool getDStarSelfOnly() const;
|
||||||
|
std::vector<std::string> getDStarBlackList() const;
|
||||||
|
bool getDStarAckReply() const;
|
||||||
|
unsigned int getDStarAckTime() const;
|
||||||
|
bool getDStarAckMessage() const;
|
||||||
|
bool getDStarErrorReply() const;
|
||||||
|
bool getDStarRemoteGateway() const;
|
||||||
|
unsigned int getDStarModeHang() const;
|
||||||
|
|
||||||
// The DMR section
|
// The DMR section
|
||||||
bool getDMREnabled() const;
|
bool getDMREnabled() const;
|
||||||
bool getDMRBeacons() const;
|
DMR_BEACONS getDMRBeacons() const;
|
||||||
|
unsigned int getDMRBeaconInterval() const;
|
||||||
|
unsigned int getDMRBeaconDuration() const;
|
||||||
unsigned int getDMRId() const;
|
unsigned int getDMRId() const;
|
||||||
unsigned int getDMRColorCode() const;
|
unsigned int getDMRColorCode() const;
|
||||||
|
bool getDMREmbeddedLCOnly() const;
|
||||||
|
bool getDMRDumpTAData() const;
|
||||||
|
bool getDMRSelfOnly() const;
|
||||||
|
std::vector<unsigned int> getDMRPrefixes() const;
|
||||||
|
std::vector<unsigned int> getDMRBlackList() const;
|
||||||
|
std::vector<unsigned int> getDMRWhiteList() const;
|
||||||
|
std::vector<unsigned int> getDMRSlot1TGWhiteList() const;
|
||||||
|
std::vector<unsigned int> getDMRSlot2TGWhiteList() const;
|
||||||
|
unsigned int getDMRCallHang() const;
|
||||||
|
unsigned int getDMRTXHang() const;
|
||||||
|
unsigned int getDMRModeHang() const;
|
||||||
|
DMR_OVCM_TYPES getDMROVCM() const;
|
||||||
|
|
||||||
// The System Fusion section
|
// The System Fusion section
|
||||||
bool getFusionEnabled() const;
|
bool getFusionEnabled() const;
|
||||||
|
bool getFusionLowDeviation() const;
|
||||||
|
bool getFusionRemoteGateway() const;
|
||||||
|
bool getFusionSelfOnly() const;
|
||||||
|
unsigned int getFusionTXHang() const;
|
||||||
|
bool getFusionDGIdEnabled() const;
|
||||||
|
unsigned char getFusionDGId() const;
|
||||||
|
unsigned int getFusionModeHang() const;
|
||||||
|
|
||||||
|
// The P25 section
|
||||||
|
bool getP25Enabled() const;
|
||||||
|
unsigned int getP25Id() const;
|
||||||
|
unsigned int getP25NAC() const;
|
||||||
|
bool getP25SelfOnly() const;
|
||||||
|
bool getP25OverrideUID() const;
|
||||||
|
bool getP25RemoteGateway() const;
|
||||||
|
unsigned int getP25TXHang() const;
|
||||||
|
unsigned int getP25ModeHang() const;
|
||||||
|
|
||||||
|
// The NXDN section
|
||||||
|
bool getNXDNEnabled() const;
|
||||||
|
unsigned int getNXDNId() const;
|
||||||
|
unsigned int getNXDNRAN() const;
|
||||||
|
bool getNXDNSelfOnly() const;
|
||||||
|
bool getNXDNRemoteGateway() const;
|
||||||
|
unsigned int getNXDNTXHang() const;
|
||||||
|
unsigned int getNXDNModeHang() const;
|
||||||
|
|
||||||
|
// The POCSAG section
|
||||||
|
bool getPOCSAGEnabled() const;
|
||||||
|
unsigned int getPOCSAGFrequency() const;
|
||||||
|
|
||||||
|
// The FM Section
|
||||||
|
bool getFMEnabled() const;
|
||||||
|
std::string getFMCallsign() const;
|
||||||
|
unsigned int getFMCallsignSpeed() const;
|
||||||
|
unsigned int getFMCallsignFrequency() const;
|
||||||
|
unsigned int getFMCallsignTime() const;
|
||||||
|
unsigned int getFMCallsignHoldoff() const;
|
||||||
|
float getFMCallsignHighLevel() const;
|
||||||
|
float getFMCallsignLowLevel() const;
|
||||||
|
bool getFMCallsignAtStart() const;
|
||||||
|
bool getFMCallsignAtEnd() const;
|
||||||
|
bool getFMCallsignAtLatch() const;
|
||||||
|
std::string getFMRFAck() const;
|
||||||
|
std::string getFMExtAck() const;
|
||||||
|
unsigned int getFMAckSpeed() const;
|
||||||
|
unsigned int getFMAckFrequency() const;
|
||||||
|
unsigned int getFMAckMinTime() const;
|
||||||
|
unsigned int getFMAckDelay() const;
|
||||||
|
float getFMAckLevel() const;
|
||||||
|
unsigned int getFMTimeout() const;
|
||||||
|
float getFMTimeoutLevel() const;
|
||||||
|
float getFMCTCSSFrequency() const;
|
||||||
|
unsigned int getFMCTCSSHighThreshold() const;
|
||||||
|
unsigned int getFMCTCSSLowThreshold() const;
|
||||||
|
float getFMCTCSSLevel() const;
|
||||||
|
unsigned int getFMKerchunkTime() const;
|
||||||
|
unsigned int getFMHangTime() const;
|
||||||
|
bool getFMUseCOS() const;
|
||||||
|
bool getFMCOSInvert() const;
|
||||||
|
unsigned int getFMRFAudioBoost() const;
|
||||||
|
float getFMMaxDevLevel() const;
|
||||||
|
unsigned int getFMExtAudioBoost() const;
|
||||||
|
|
||||||
// The D-Star Network section
|
// The D-Star Network section
|
||||||
bool getDStarNetworkEnabled() const;
|
bool getDStarNetworkEnabled() const;
|
||||||
std::string getDStarGatewayAddress() const;
|
std::string getDStarGatewayAddress() const;
|
||||||
unsigned int getDStarGatewayPort() const;
|
unsigned int getDStarGatewayPort() const;
|
||||||
unsigned int getDStarLocalPort() const;
|
unsigned int getDStarLocalPort() const;
|
||||||
|
unsigned int getDStarNetworkModeHang() const;
|
||||||
bool getDStarNetworkDebug() const;
|
bool getDStarNetworkDebug() const;
|
||||||
|
|
||||||
// The DMR Network section
|
// The DMR Network section
|
||||||
bool getDMRNetworkEnabled() const;
|
bool getDMRNetworkEnabled() const;
|
||||||
std::string getDMRNetworkAddress() const;
|
std::string getDMRNetworkAddress() const;
|
||||||
unsigned int getDMRNetworkPort() const;
|
unsigned int getDMRNetworkPort() const;
|
||||||
|
unsigned int getDMRNetworkLocal() const;
|
||||||
std::string getDMRNetworkPassword() const;
|
std::string getDMRNetworkPassword() const;
|
||||||
|
std::string getDMRNetworkOptions() const;
|
||||||
bool getDMRNetworkDebug() const;
|
bool getDMRNetworkDebug() const;
|
||||||
|
unsigned int getDMRNetworkJitter() const;
|
||||||
|
bool getDMRNetworkSlot1() const;
|
||||||
|
bool getDMRNetworkSlot2() const;
|
||||||
|
unsigned int getDMRNetworkModeHang() const;
|
||||||
|
|
||||||
// The System Fusion Network section
|
// The System Fusion Network section
|
||||||
bool getFusionNetworkEnabled() const;
|
bool getFusionNetworkEnabled() const;
|
||||||
std::string getFusionNetworkAddress() const;
|
std::string getFusionNetworkMyAddress() const;
|
||||||
unsigned int getFusionNetworkPort() const;
|
unsigned int getFusionNetworkMyPort() const;
|
||||||
|
std::string getFusionNetworkGatewayAddress() const;
|
||||||
|
unsigned int getFusionNetworkGatewayPort() const;
|
||||||
|
unsigned int getFusionNetworkModeHang() const;
|
||||||
bool getFusionNetworkDebug() const;
|
bool getFusionNetworkDebug() const;
|
||||||
|
|
||||||
|
// The P25 Network section
|
||||||
|
bool getP25NetworkEnabled() const;
|
||||||
|
std::string getP25GatewayAddress() const;
|
||||||
|
unsigned int getP25GatewayPort() const;
|
||||||
|
unsigned int getP25LocalPort() const;
|
||||||
|
unsigned int getP25NetworkModeHang() const;
|
||||||
|
bool getP25NetworkDebug() const;
|
||||||
|
|
||||||
|
// The NXDN Network section
|
||||||
|
bool getNXDNNetworkEnabled() const;
|
||||||
|
std::string getNXDNNetworkProtocol() const;
|
||||||
|
std::string getNXDNGatewayAddress() const;
|
||||||
|
unsigned int getNXDNGatewayPort() const;
|
||||||
|
std::string getNXDNLocalAddress() const;
|
||||||
|
unsigned int getNXDNLocalPort() const;
|
||||||
|
unsigned int getNXDNNetworkModeHang() const;
|
||||||
|
bool getNXDNNetworkDebug() const;
|
||||||
|
|
||||||
|
// The POCSAG Network section
|
||||||
|
bool getPOCSAGNetworkEnabled() const;
|
||||||
|
std::string getPOCSAGGatewayAddress() const;
|
||||||
|
unsigned int getPOCSAGGatewayPort() const;
|
||||||
|
std::string getPOCSAGLocalAddress() const;
|
||||||
|
unsigned int getPOCSAGLocalPort() const;
|
||||||
|
unsigned int getPOCSAGNetworkModeHang() const;
|
||||||
|
bool getPOCSAGNetworkDebug() const;
|
||||||
|
|
||||||
// The TFTSERIAL section
|
// The TFTSERIAL section
|
||||||
std::string getTFTSerialPort() const;
|
std::string getTFTSerialPort() const;
|
||||||
|
unsigned int getTFTSerialBrightness() const;
|
||||||
|
|
||||||
|
// The HD44780 section
|
||||||
|
unsigned int getHD44780Rows() const;
|
||||||
|
unsigned int getHD44780Columns() const;
|
||||||
|
std::vector<unsigned int> getHD44780Pins() const;
|
||||||
|
unsigned int getHD44780i2cAddress() const;
|
||||||
|
bool getHD44780PWM() const;
|
||||||
|
unsigned int getHD44780PWMPin() const;
|
||||||
|
unsigned int getHD44780PWMBright() const;
|
||||||
|
unsigned int getHD44780PWMDim() const;
|
||||||
|
bool getHD44780DisplayClock() const;
|
||||||
|
bool getHD44780UTC() const;
|
||||||
|
|
||||||
|
// The Nextion section
|
||||||
|
std::string getNextionPort() const;
|
||||||
|
unsigned int getNextionBrightness() const;
|
||||||
|
bool getNextionDisplayClock() const;
|
||||||
|
bool getNextionUTC() const;
|
||||||
|
unsigned int getNextionIdleBrightness() const;
|
||||||
|
unsigned int getNextionScreenLayout() const;
|
||||||
|
bool getNextionTempInFahrenheit() const;
|
||||||
|
|
||||||
|
// The OLED section
|
||||||
|
unsigned char getOLEDType() const;
|
||||||
|
unsigned char getOLEDBrightness() const;
|
||||||
|
bool getOLEDInvert() const;
|
||||||
|
bool getOLEDScroll() const;
|
||||||
|
bool getOLEDRotate() const;
|
||||||
|
bool getOLEDLogoScreensaver() const;
|
||||||
|
|
||||||
|
// The LCDproc section
|
||||||
|
std::string getLCDprocAddress() const;
|
||||||
|
unsigned int getLCDprocPort() const;
|
||||||
|
unsigned int getLCDprocLocalPort() const;
|
||||||
|
bool getLCDprocDisplayClock() const;
|
||||||
|
bool getLCDprocUTC() const;
|
||||||
|
bool getLCDprocDimOnIdle() const;
|
||||||
|
|
||||||
|
// The Lock File section
|
||||||
|
bool getLockFileEnabled() const;
|
||||||
|
std::string getLockFileName() const;
|
||||||
|
|
||||||
|
// The Mobile GPS section
|
||||||
|
bool getMobileGPSEnabled() const;
|
||||||
|
std::string getMobileGPSAddress() const;
|
||||||
|
unsigned int getMobileGPSPort() const;
|
||||||
|
|
||||||
|
// The Remote Control section
|
||||||
|
bool getRemoteControlEnabled() const;
|
||||||
|
unsigned int getRemoteControlPort() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_file;
|
std::string m_file;
|
||||||
std::string m_callsign;
|
std::string m_callsign;
|
||||||
|
unsigned int m_id;
|
||||||
unsigned int m_timeout;
|
unsigned int m_timeout;
|
||||||
bool m_duplex;
|
bool m_duplex;
|
||||||
unsigned int m_modeHang;
|
|
||||||
std::string m_display;
|
std::string m_display;
|
||||||
|
bool m_daemon;
|
||||||
|
|
||||||
unsigned int m_rxFrequency;
|
unsigned int m_rxFrequency;
|
||||||
unsigned int m_txFrequency;
|
unsigned int m_txFrequency;
|
||||||
|
@ -117,48 +334,243 @@ private:
|
||||||
std::string m_description;
|
std::string m_description;
|
||||||
std::string m_url;
|
std::string m_url;
|
||||||
|
|
||||||
unsigned int m_logLevel;
|
unsigned int m_logDisplayLevel;
|
||||||
std::string m_logPath;
|
unsigned int m_logFileLevel;
|
||||||
std::string m_logRoot;
|
std::string m_logFilePath;
|
||||||
bool m_logDisplay;
|
std::string m_logFileRoot;
|
||||||
|
|
||||||
|
bool m_cwIdEnabled;
|
||||||
|
unsigned int m_cwIdTime;
|
||||||
|
std::string m_cwIdCallsign;
|
||||||
|
|
||||||
|
std::string m_dmrIdLookupFile;
|
||||||
|
unsigned int m_dmrIdLookupTime;
|
||||||
|
|
||||||
|
std::string m_nxdnIdLookupFile;
|
||||||
|
unsigned int m_nxdnIdLookupTime;
|
||||||
|
|
||||||
std::string m_modemPort;
|
std::string m_modemPort;
|
||||||
|
std::string m_modemProtocol;
|
||||||
|
unsigned int m_modemAddress;
|
||||||
bool m_modemRXInvert;
|
bool m_modemRXInvert;
|
||||||
bool m_modemTXInvert;
|
bool m_modemTXInvert;
|
||||||
bool m_modemPTTInvert;
|
bool m_modemPTTInvert;
|
||||||
unsigned int m_modemTXDelay;
|
unsigned int m_modemTXDelay;
|
||||||
unsigned int m_modemRXLevel;
|
unsigned int m_modemDMRDelay;
|
||||||
unsigned int m_modemTXLevel;
|
int m_modemTXOffset;
|
||||||
|
int m_modemRXOffset;
|
||||||
|
int m_modemRXDCOffset;
|
||||||
|
int m_modemTXDCOffset;
|
||||||
|
float m_modemRFLevel;
|
||||||
|
float m_modemRXLevel;
|
||||||
|
float m_modemCWIdTXLevel;
|
||||||
|
float m_modemDStarTXLevel;
|
||||||
|
float m_modemDMRTXLevel;
|
||||||
|
float m_modemYSFTXLevel;
|
||||||
|
float m_modemP25TXLevel;
|
||||||
|
float m_modemNXDNTXLevel;
|
||||||
|
float m_modemPOCSAGTXLevel;
|
||||||
|
float m_modemFMTXLevel;
|
||||||
|
std::string m_modemRSSIMappingFile;
|
||||||
|
bool m_modemTrace;
|
||||||
bool m_modemDebug;
|
bool m_modemDebug;
|
||||||
|
|
||||||
|
bool m_transparentEnabled;
|
||||||
|
std::string m_transparentRemoteAddress;
|
||||||
|
unsigned int m_transparentRemotePort;
|
||||||
|
unsigned int m_transparentLocalPort;
|
||||||
|
unsigned int m_transparentSendFrameType;
|
||||||
|
|
||||||
|
bool m_umpEnabled;
|
||||||
|
std::string m_umpPort;
|
||||||
|
|
||||||
bool m_dstarEnabled;
|
bool m_dstarEnabled;
|
||||||
std::string m_dstarModule;
|
std::string m_dstarModule;
|
||||||
|
bool m_dstarSelfOnly;
|
||||||
|
std::vector<std::string> m_dstarBlackList;
|
||||||
|
bool m_dstarAckReply;
|
||||||
|
unsigned int m_dstarAckTime;
|
||||||
|
bool m_dstarAckMessage;
|
||||||
|
bool m_dstarErrorReply;
|
||||||
|
bool m_dstarRemoteGateway;
|
||||||
|
unsigned int m_dstarModeHang;
|
||||||
|
|
||||||
bool m_dmrEnabled;
|
bool m_dmrEnabled;
|
||||||
bool m_dmrBeacons;
|
DMR_BEACONS m_dmrBeacons;
|
||||||
|
unsigned int m_dmrBeaconInterval;
|
||||||
|
unsigned int m_dmrBeaconDuration;
|
||||||
unsigned int m_dmrId;
|
unsigned int m_dmrId;
|
||||||
unsigned int m_dmrColorCode;
|
unsigned int m_dmrColorCode;
|
||||||
|
bool m_dmrSelfOnly;
|
||||||
|
bool m_dmrEmbeddedLCOnly;
|
||||||
|
bool m_dmrDumpTAData;
|
||||||
|
std::vector<unsigned int> m_dmrPrefixes;
|
||||||
|
std::vector<unsigned int> m_dmrBlackList;
|
||||||
|
std::vector<unsigned int> m_dmrWhiteList;
|
||||||
|
std::vector<unsigned int> m_dmrSlot1TGWhiteList;
|
||||||
|
std::vector<unsigned int> m_dmrSlot2TGWhiteList;
|
||||||
|
unsigned int m_dmrCallHang;
|
||||||
|
unsigned int m_dmrTXHang;
|
||||||
|
unsigned int m_dmrModeHang;
|
||||||
|
DMR_OVCM_TYPES m_dmrOVCM;
|
||||||
|
|
||||||
bool m_fusionEnabled;
|
bool m_fusionEnabled;
|
||||||
|
bool m_fusionLowDeviation;
|
||||||
|
bool m_fusionRemoteGateway;
|
||||||
|
bool m_fusionSelfOnly;
|
||||||
|
unsigned int m_fusionTXHang;
|
||||||
|
bool m_fusionDGIdEnabled;
|
||||||
|
unsigned char m_fusionDGId;
|
||||||
|
unsigned int m_fusionModeHang;
|
||||||
|
|
||||||
|
bool m_p25Enabled;
|
||||||
|
unsigned int m_p25Id;
|
||||||
|
unsigned int m_p25NAC;
|
||||||
|
bool m_p25SelfOnly;
|
||||||
|
bool m_p25OverrideUID;
|
||||||
|
bool m_p25RemoteGateway;
|
||||||
|
unsigned int m_p25TXHang;
|
||||||
|
unsigned int m_p25ModeHang;
|
||||||
|
|
||||||
|
bool m_nxdnEnabled;
|
||||||
|
unsigned int m_nxdnId;
|
||||||
|
unsigned int m_nxdnRAN;
|
||||||
|
bool m_nxdnSelfOnly;
|
||||||
|
bool m_nxdnRemoteGateway;
|
||||||
|
unsigned int m_nxdnTXHang;
|
||||||
|
unsigned int m_nxdnModeHang;
|
||||||
|
|
||||||
|
bool m_pocsagEnabled;
|
||||||
|
unsigned int m_pocsagFrequency;
|
||||||
|
|
||||||
|
bool m_fmEnabled;
|
||||||
|
std::string m_fmCallsign;
|
||||||
|
unsigned int m_fmCallsignSpeed;
|
||||||
|
unsigned int m_fmCallsignFrequency;
|
||||||
|
unsigned int m_fmCallsignTime;
|
||||||
|
unsigned int m_fmCallsignHoldoff;
|
||||||
|
float m_fmCallsignHighLevel;
|
||||||
|
float m_fmCallsignLowLevel;
|
||||||
|
bool m_fmCallsignAtStart;
|
||||||
|
bool m_fmCallsignAtEnd;
|
||||||
|
bool m_fmCallsignAtLatch;
|
||||||
|
std::string m_fmRFAck;
|
||||||
|
std::string m_fmExtAck;
|
||||||
|
unsigned int m_fmAckSpeed;
|
||||||
|
unsigned int m_fmAckFrequency;
|
||||||
|
unsigned int m_fmAckMinTime;
|
||||||
|
unsigned int m_fmAckDelay;
|
||||||
|
float m_fmAckLevel;
|
||||||
|
unsigned int m_fmTimeout;
|
||||||
|
float m_fmTimeoutLevel;
|
||||||
|
float m_fmCTCSSFrequency;
|
||||||
|
unsigned int m_fmCTCSSHighThreshold;
|
||||||
|
unsigned int m_fmCTCSSLowThreshold;
|
||||||
|
float m_fmCTCSSLevel;
|
||||||
|
unsigned int m_fmKerchunkTime;
|
||||||
|
unsigned int m_fmHangTime;
|
||||||
|
bool m_fmUseCOS;
|
||||||
|
bool m_fmCOSInvert;
|
||||||
|
unsigned int m_fmRFAudioBoost;
|
||||||
|
float m_fmMaxDevLevel;
|
||||||
|
unsigned int m_fmExtAudioBoost;
|
||||||
|
|
||||||
bool m_dstarNetworkEnabled;
|
bool m_dstarNetworkEnabled;
|
||||||
std::string m_dstarGatewayAddress;
|
std::string m_dstarGatewayAddress;
|
||||||
unsigned int m_dstarGatewayPort;
|
unsigned int m_dstarGatewayPort;
|
||||||
unsigned int m_dstarLocalPort;
|
unsigned int m_dstarLocalPort;
|
||||||
|
unsigned int m_dstarNetworkModeHang;
|
||||||
bool m_dstarNetworkDebug;
|
bool m_dstarNetworkDebug;
|
||||||
|
|
||||||
bool m_dmrNetworkEnabled;
|
bool m_dmrNetworkEnabled;
|
||||||
std::string m_dmrNetworkAddress;
|
std::string m_dmrNetworkAddress;
|
||||||
unsigned int m_dmrNetworkPort;
|
unsigned int m_dmrNetworkPort;
|
||||||
|
unsigned int m_dmrNetworkLocal;
|
||||||
std::string m_dmrNetworkPassword;
|
std::string m_dmrNetworkPassword;
|
||||||
|
std::string m_dmrNetworkOptions;
|
||||||
bool m_dmrNetworkDebug;
|
bool m_dmrNetworkDebug;
|
||||||
|
unsigned int m_dmrNetworkJitter;
|
||||||
|
bool m_dmrNetworkSlot1;
|
||||||
|
bool m_dmrNetworkSlot2;
|
||||||
|
unsigned int m_dmrNetworkModeHang;
|
||||||
|
|
||||||
bool m_fusionNetworkEnabled;
|
bool m_fusionNetworkEnabled;
|
||||||
std::string m_fusionNetworkAddress;
|
std::string m_fusionNetworkMyAddress;
|
||||||
unsigned int m_fusionNetworkPort;
|
unsigned int m_fusionNetworkMyPort;
|
||||||
|
std::string m_fusionNetworkGatewayAddress;
|
||||||
|
unsigned int m_fusionNetworkGatewayPort;
|
||||||
|
unsigned int m_fusionNetworkModeHang;
|
||||||
bool m_fusionNetworkDebug;
|
bool m_fusionNetworkDebug;
|
||||||
|
|
||||||
|
bool m_p25NetworkEnabled;
|
||||||
|
std::string m_p25GatewayAddress;
|
||||||
|
unsigned int m_p25GatewayPort;
|
||||||
|
unsigned int m_p25LocalPort;
|
||||||
|
unsigned int m_p25NetworkModeHang;
|
||||||
|
bool m_p25NetworkDebug;
|
||||||
|
|
||||||
|
bool m_nxdnNetworkEnabled;
|
||||||
|
std::string m_nxdnNetworkProtocol;
|
||||||
|
std::string m_nxdnGatewayAddress;
|
||||||
|
unsigned int m_nxdnGatewayPort;
|
||||||
|
std::string m_nxdnLocalAddress;
|
||||||
|
unsigned int m_nxdnLocalPort;
|
||||||
|
unsigned int m_nxdnNetworkModeHang;
|
||||||
|
bool m_nxdnNetworkDebug;
|
||||||
|
|
||||||
|
bool m_pocsagNetworkEnabled;
|
||||||
|
std::string m_pocsagGatewayAddress;
|
||||||
|
unsigned int m_pocsagGatewayPort;
|
||||||
|
std::string m_pocsagLocalAddress;
|
||||||
|
unsigned int m_pocsagLocalPort;
|
||||||
|
unsigned int m_pocsagNetworkModeHang;
|
||||||
|
bool m_pocsagNetworkDebug;
|
||||||
|
|
||||||
std::string m_tftSerialPort;
|
std::string m_tftSerialPort;
|
||||||
|
unsigned int m_tftSerialBrightness;
|
||||||
|
|
||||||
|
unsigned int m_hd44780Rows;
|
||||||
|
unsigned int m_hd44780Columns;
|
||||||
|
std::vector<unsigned int> m_hd44780Pins;
|
||||||
|
unsigned int m_hd44780i2cAddress;
|
||||||
|
bool m_hd44780PWM;
|
||||||
|
unsigned int m_hd44780PWMPin;
|
||||||
|
unsigned int m_hd44780PWMBright;
|
||||||
|
unsigned int m_hd44780PWMDim;
|
||||||
|
bool m_hd44780DisplayClock;
|
||||||
|
bool m_hd44780UTC;
|
||||||
|
|
||||||
|
std::string m_nextionPort;
|
||||||
|
unsigned int m_nextionBrightness;
|
||||||
|
bool m_nextionDisplayClock;
|
||||||
|
bool m_nextionUTC;
|
||||||
|
unsigned int m_nextionIdleBrightness;
|
||||||
|
unsigned int m_nextionScreenLayout;
|
||||||
|
bool m_nextionTempInFahrenheit;
|
||||||
|
|
||||||
|
unsigned char m_oledType;
|
||||||
|
unsigned char m_oledBrightness;
|
||||||
|
bool m_oledInvert;
|
||||||
|
bool m_oledScroll;
|
||||||
|
bool m_oledRotate;
|
||||||
|
bool m_oledLogoScreensaver;
|
||||||
|
|
||||||
|
std::string m_lcdprocAddress;
|
||||||
|
unsigned int m_lcdprocPort;
|
||||||
|
unsigned int m_lcdprocLocalPort;
|
||||||
|
bool m_lcdprocDisplayClock;
|
||||||
|
bool m_lcdprocUTC;
|
||||||
|
bool m_lcdprocDimOnIdle;
|
||||||
|
|
||||||
|
bool m_lockFileEnabled;
|
||||||
|
std::string m_lockFileName;
|
||||||
|
|
||||||
|
bool m_mobileGPSEnabled;
|
||||||
|
std::string m_mobileGPSAddress;
|
||||||
|
unsigned int m_mobileGPSPort;
|
||||||
|
|
||||||
|
bool m_remoteControlEnabled;
|
||||||
|
unsigned int m_remoteControlPort;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
99
DMRAccessControl.cpp
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 by Simon Rune G7RZU
|
||||||
|
* Copyright (C) 2016,2017 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "DMRAccessControl.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
std::vector<unsigned int> CDMRAccessControl::m_blackList;
|
||||||
|
std::vector<unsigned int> CDMRAccessControl::m_whiteList;
|
||||||
|
|
||||||
|
std::vector<unsigned int> CDMRAccessControl::m_prefixes;
|
||||||
|
|
||||||
|
std::vector<unsigned int> CDMRAccessControl::m_slot1TGWhiteList;
|
||||||
|
std::vector<unsigned int> CDMRAccessControl::m_slot2TGWhiteList;
|
||||||
|
|
||||||
|
bool CDMRAccessControl::m_selfOnly = false;
|
||||||
|
|
||||||
|
unsigned int CDMRAccessControl::m_id = 0U;
|
||||||
|
|
||||||
|
void CDMRAccessControl::init(const std::vector<unsigned int>& blacklist, const std::vector<unsigned int>& whitelist, const std::vector<unsigned int>& slot1TGWhitelist, const std::vector<unsigned int>& slot2TGWhitelist, bool selfOnly, const std::vector<unsigned int>& prefixes, unsigned int id)
|
||||||
|
{
|
||||||
|
m_slot1TGWhiteList = slot1TGWhitelist;
|
||||||
|
m_slot2TGWhiteList = slot2TGWhitelist;
|
||||||
|
m_blackList = blacklist;
|
||||||
|
m_whiteList = whitelist;
|
||||||
|
m_selfOnly = selfOnly;
|
||||||
|
m_prefixes = prefixes;
|
||||||
|
m_id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMRAccessControl::validateSrcId(unsigned int id)
|
||||||
|
{
|
||||||
|
if (m_selfOnly) {
|
||||||
|
if (m_id > 99999999U) // Check that the Config DMR-ID is bigger than 8 digits
|
||||||
|
return id == m_id / 100U; // Does RF ID match Config ID / 100
|
||||||
|
else if (m_id > 9999999U) // Check that the Config DMR-ID is bigger than 7 digits
|
||||||
|
return id == m_id / 10U; // Does RF ID match Config ID / 10
|
||||||
|
else
|
||||||
|
return id == m_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::find(m_blackList.begin(), m_blackList.end(), id) != m_blackList.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
unsigned int prefix = id / 10000U;
|
||||||
|
if (prefix == 0U || prefix > 999U)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!m_prefixes.empty()) {
|
||||||
|
bool ret = std::find(m_prefixes.begin(), m_prefixes.end(), prefix) == m_prefixes.end();
|
||||||
|
if (ret)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_whiteList.empty())
|
||||||
|
return std::find(m_whiteList.begin(), m_whiteList.end(), id) != m_whiteList.end();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMRAccessControl::validateTGId(unsigned int slotNo, bool group, unsigned int id)
|
||||||
|
{
|
||||||
|
if (!group)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// TG0 is never valid
|
||||||
|
if (id == 0U)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (slotNo == 1U) {
|
||||||
|
if (m_slot1TGWhiteList.empty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return std::find(m_slot1TGWhiteList.begin(), m_slot1TGWhiteList.end(), id) != m_slot1TGWhiteList.end();
|
||||||
|
} else {
|
||||||
|
if (m_slot2TGWhiteList.empty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return std::find(m_slot2TGWhiteList.begin(), m_slot2TGWhiteList.end(), id) != m_slot2TGWhiteList.end();
|
||||||
|
}
|
||||||
|
}
|
44
DMRAccessControl.h
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 by Simon Rune G7RZU
|
||||||
|
* Copyright (C) 2016,2017 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
*/
|
||||||
|
#if !defined(DMRAccessControl_H)
|
||||||
|
#define DMRAccessControl_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class CDMRAccessControl {
|
||||||
|
public:
|
||||||
|
static bool validateSrcId(unsigned int id);
|
||||||
|
|
||||||
|
static bool validateTGId(unsigned int slotNo, bool group, unsigned int id);
|
||||||
|
|
||||||
|
static void init(const std::vector<unsigned int>& blacklist, const std::vector<unsigned int>& whitelist, const std::vector<unsigned int>& slot1TGWhitelist, const std::vector<unsigned int>& slot2TGWhitelist, bool selfOnly, const std::vector<unsigned int>& prefixes, unsigned int id);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::vector<unsigned int> m_blackList;
|
||||||
|
static std::vector<unsigned int> m_whiteList;
|
||||||
|
|
||||||
|
static std::vector<unsigned int> m_prefixes;
|
||||||
|
|
||||||
|
static std::vector<unsigned int> m_slot1TGWhiteList;
|
||||||
|
static std::vector<unsigned int> m_slot2TGWhiteList;
|
||||||
|
|
||||||
|
static bool m_selfOnly;
|
||||||
|
static unsigned int m_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
225
DMRCSBK.cpp
Normal file
|
@ -0,0 +1,225 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2019 by Patrick Maier DK5MP
|
||||||
|
*
|
||||||
|
* 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 "DMRCSBK.h"
|
||||||
|
#include "BPTC19696.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
#include "CRC.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
CDMRCSBK::CDMRCSBK() :
|
||||||
|
m_data(NULL),
|
||||||
|
m_CSBKO(CSBKO_NONE),
|
||||||
|
m_FID(0x00U),
|
||||||
|
m_GI(false),
|
||||||
|
m_bsId(0U),
|
||||||
|
m_srcId(0U),
|
||||||
|
m_dstId(0U),
|
||||||
|
m_dataContent(false),
|
||||||
|
m_CBF(0U)
|
||||||
|
{
|
||||||
|
m_data = new unsigned char[12U];
|
||||||
|
}
|
||||||
|
|
||||||
|
CDMRCSBK::~CDMRCSBK()
|
||||||
|
{
|
||||||
|
delete[] m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMRCSBK::put(const unsigned char* bytes)
|
||||||
|
{
|
||||||
|
assert(bytes != NULL);
|
||||||
|
|
||||||
|
CBPTC19696 bptc;
|
||||||
|
bptc.decode(bytes, m_data);
|
||||||
|
|
||||||
|
m_data[10U] ^= CSBK_CRC_MASK[0U];
|
||||||
|
m_data[11U] ^= CSBK_CRC_MASK[1U];
|
||||||
|
|
||||||
|
bool valid = CCRC::checkCCITT162(m_data, 12U);
|
||||||
|
if (!valid)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Restore the checksum
|
||||||
|
m_data[10U] ^= CSBK_CRC_MASK[0U];
|
||||||
|
m_data[11U] ^= CSBK_CRC_MASK[1U];
|
||||||
|
|
||||||
|
m_CSBKO = CSBKO(m_data[0U] & 0x3FU);
|
||||||
|
m_FID = m_data[1U];
|
||||||
|
|
||||||
|
switch (m_CSBKO) {
|
||||||
|
case CSBKO_BSDWNACT:
|
||||||
|
m_GI = false;
|
||||||
|
m_bsId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U];
|
||||||
|
m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U];
|
||||||
|
m_dataContent = false;
|
||||||
|
m_CBF = 0U;
|
||||||
|
CUtils::dump(1U, "Downlink Activate CSBK", m_data, 12U);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CSBKO_UUVREQ:
|
||||||
|
m_GI = false;
|
||||||
|
m_dstId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U];
|
||||||
|
m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U];
|
||||||
|
m_dataContent = false;
|
||||||
|
m_CBF = 0U;
|
||||||
|
CUtils::dump(1U, "Unit to Unit Service Request CSBK", m_data, 12U);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CSBKO_UUANSRSP:
|
||||||
|
m_GI = false;
|
||||||
|
m_dstId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U];
|
||||||
|
m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U];
|
||||||
|
m_dataContent = false;
|
||||||
|
m_CBF = 0U;
|
||||||
|
CUtils::dump(1U, "Unit to Unit Service Answer Response CSBK", m_data, 12U);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CSBKO_PRECCSBK:
|
||||||
|
m_GI = (m_data[2U] & 0x40U) == 0x40U;
|
||||||
|
m_dstId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U];
|
||||||
|
m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U];
|
||||||
|
m_dataContent = (m_data[2U] & 0x80U) == 0x80U;
|
||||||
|
m_CBF = m_data[3U];
|
||||||
|
CUtils::dump(1U, "Preamble CSBK", m_data, 12U);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CSBKO_NACKRSP:
|
||||||
|
m_GI = false;
|
||||||
|
m_srcId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U];
|
||||||
|
m_dstId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U];
|
||||||
|
m_dataContent = false;
|
||||||
|
m_CBF = 0U;
|
||||||
|
CUtils::dump(1U, "Negative Acknowledge Response CSBK", m_data, 12U);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CSBKO_CALL_ALERT:
|
||||||
|
m_GI = false;
|
||||||
|
m_dstId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U];
|
||||||
|
m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U];
|
||||||
|
m_dataContent = false;
|
||||||
|
m_CBF = 0U;
|
||||||
|
CUtils::dump(1U, "Call Alert CSBK", m_data, 12U);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CSBKO_CALL_ALERT_ACK:
|
||||||
|
m_GI = false;
|
||||||
|
m_dstId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U];
|
||||||
|
m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U];
|
||||||
|
m_dataContent = false;
|
||||||
|
m_CBF = 0U;
|
||||||
|
CUtils::dump(1U, "Call Alert Ack CSBK", m_data, 12U);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
m_GI = false;
|
||||||
|
m_srcId = 0U;
|
||||||
|
m_dstId = 0U;
|
||||||
|
m_dataContent = false;
|
||||||
|
m_CBF = 0U;
|
||||||
|
CUtils::dump("Unhandled CSBK type", m_data, 12U);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMRCSBK::get(unsigned char* bytes) const
|
||||||
|
{
|
||||||
|
assert(bytes != NULL);
|
||||||
|
|
||||||
|
m_data[10U] ^= CSBK_CRC_MASK[0U];
|
||||||
|
m_data[11U] ^= CSBK_CRC_MASK[1U];
|
||||||
|
|
||||||
|
CCRC::addCCITT162(m_data, 12U);
|
||||||
|
|
||||||
|
m_data[10U] ^= CSBK_CRC_MASK[0U];
|
||||||
|
m_data[11U] ^= CSBK_CRC_MASK[1U];
|
||||||
|
|
||||||
|
CBPTC19696 bptc;
|
||||||
|
bptc.encode(m_data, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
CSBKO CDMRCSBK::getCSBKO() const
|
||||||
|
{
|
||||||
|
return m_CSBKO;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char CDMRCSBK::getFID() const
|
||||||
|
{
|
||||||
|
return m_FID;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMRCSBK::getOVCM() const
|
||||||
|
{
|
||||||
|
bool bOVCM = false;
|
||||||
|
// Service options informations are only available in
|
||||||
|
// "Unit to Unit Voice Service Request CSBK" and
|
||||||
|
// "Unit to Unit Voice Service Answer Response CSBK"
|
||||||
|
if ((m_CSBKO == CSBKO_UUVREQ) || (m_CSBKO == CSBKO_UUANSRSP))
|
||||||
|
bOVCM = (m_data[2U] & 0x04U) == 0x04U;
|
||||||
|
|
||||||
|
return bOVCM;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMRCSBK::setOVCM(bool ovcm)
|
||||||
|
{
|
||||||
|
// Set OVCM only in CSBKs having the service options information
|
||||||
|
if ((m_CSBKO == CSBKO_UUVREQ) || (m_CSBKO == CSBKO_UUANSRSP)) {
|
||||||
|
if (ovcm)
|
||||||
|
m_data[2U] |= 0x04U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMRCSBK::getGI() const
|
||||||
|
{
|
||||||
|
return m_GI;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CDMRCSBK::getBSId() const
|
||||||
|
{
|
||||||
|
return m_bsId;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CDMRCSBK::getSrcId() const
|
||||||
|
{
|
||||||
|
return m_srcId;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CDMRCSBK::getDstId() const
|
||||||
|
{
|
||||||
|
return m_dstId;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMRCSBK::getDataContent() const
|
||||||
|
{
|
||||||
|
return m_dataContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char CDMRCSBK::getCBF() const
|
||||||
|
{
|
||||||
|
return m_CBF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMRCSBK::setCBF(unsigned char cbf)
|
||||||
|
{
|
||||||
|
m_CBF = m_data[3U] = cbf;
|
||||||
|
}
|
80
DMRCSBK.h
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016,2020 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(DMRCSBK_H)
|
||||||
|
#define DMRCSBK_H
|
||||||
|
|
||||||
|
#include "DMRDefines.h"
|
||||||
|
|
||||||
|
enum CSBKO {
|
||||||
|
CSBKO_NONE = 0x00,
|
||||||
|
CSBKO_UUVREQ = 0x04,
|
||||||
|
CSBKO_UUANSRSP = 0x05,
|
||||||
|
CSBKO_CTCSBK = 0x07,
|
||||||
|
CSBKO_CALL_ALERT = 0x1F,
|
||||||
|
CSBKO_CALL_ALERT_ACK = 0x20,
|
||||||
|
CSBKO_NACKRSP = 0x26,
|
||||||
|
CSBKO_BSDWNACT = 0x38,
|
||||||
|
CSBKO_PRECCSBK = 0x3D
|
||||||
|
};
|
||||||
|
|
||||||
|
class CDMRCSBK
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CDMRCSBK();
|
||||||
|
~CDMRCSBK();
|
||||||
|
|
||||||
|
bool put(const unsigned char* bytes);
|
||||||
|
|
||||||
|
void get(unsigned char* bytes) const;
|
||||||
|
|
||||||
|
// Generic fields
|
||||||
|
CSBKO getCSBKO() const;
|
||||||
|
unsigned char getFID() const;
|
||||||
|
|
||||||
|
// Set/Get the OVCM bit in the supported CSBKs
|
||||||
|
bool getOVCM() const;
|
||||||
|
void setOVCM(bool ovcm);
|
||||||
|
|
||||||
|
// For BS Dwn Act
|
||||||
|
unsigned int getBSId() const;
|
||||||
|
|
||||||
|
// For Pre
|
||||||
|
bool getGI() const;
|
||||||
|
|
||||||
|
unsigned int getSrcId() const;
|
||||||
|
unsigned int getDstId() const;
|
||||||
|
|
||||||
|
bool getDataContent() const;
|
||||||
|
unsigned char getCBF() const;
|
||||||
|
|
||||||
|
void setCBF(unsigned char cbf);
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned char* m_data;
|
||||||
|
CSBKO m_CSBKO;
|
||||||
|
unsigned char m_FID;
|
||||||
|
bool m_GI;
|
||||||
|
unsigned int m_bsId;
|
||||||
|
unsigned int m_srcId;
|
||||||
|
unsigned int m_dstId;
|
||||||
|
bool m_dataContent;
|
||||||
|
unsigned char m_CBF;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016 Jonathan Naylor, G4KLX
|
* Copyright (C) 2015-2019 Jonathan Naylor, G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -12,24 +12,33 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "DMRControl.h"
|
#include "DMRControl.h"
|
||||||
|
#include "DMRAccessControl.h"
|
||||||
#include "Defines.h"
|
#include "Defines.h"
|
||||||
#include "CSBK.h"
|
#include "DMRCSBK.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
CDMRControl::CDMRControl(unsigned int id, unsigned int colorCode, unsigned int timeout, CModem* modem, CHomebrewDMRIPSC* network, IDisplay* display) :
|
CDMRControl::CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector<unsigned int>& prefixes, const std::vector<unsigned int>& blacklist, const std::vector<unsigned int>& whitelist, const std::vector<unsigned int>& slot1TGWhitelist, const std::vector<unsigned int>& slot2TGWhitelist, unsigned int timeout, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter, DMR_OVCM_TYPES ovcm) :
|
||||||
m_id(id),
|
|
||||||
m_colorCode(colorCode),
|
m_colorCode(colorCode),
|
||||||
m_modem(modem),
|
m_modem(modem),
|
||||||
m_network(network),
|
m_network(network),
|
||||||
m_slot1(1U, timeout),
|
m_slot1(1U, timeout),
|
||||||
m_slot2(2U, timeout)
|
m_slot2(2U, timeout),
|
||||||
|
m_lookup(lookup)
|
||||||
{
|
{
|
||||||
|
assert(id != 0U);
|
||||||
assert(modem != NULL);
|
assert(modem != NULL);
|
||||||
assert(display != NULL);
|
assert(display != NULL);
|
||||||
|
assert(lookup != NULL);
|
||||||
|
assert(rssi != NULL);
|
||||||
|
|
||||||
CDMRSlot::init(colorCode, modem, network, display);
|
// Load black and white lists to DMRAccessControl
|
||||||
|
CDMRAccessControl::init(blacklist, whitelist, slot1TGWhitelist, slot2TGWhitelist, selfOnly, prefixes, id);
|
||||||
|
|
||||||
|
CDMRSlot::init(colorCode, embeddedLCOnly, dumpTAData, callHang, modem, network, display, duplex, m_lookup, rssi, jitter, ovcm);
|
||||||
}
|
}
|
||||||
|
|
||||||
CDMRControl::~CDMRControl()
|
CDMRControl::~CDMRControl()
|
||||||
|
@ -38,49 +47,64 @@ CDMRControl::~CDMRControl()
|
||||||
|
|
||||||
bool CDMRControl::processWakeup(const unsigned char* data)
|
bool CDMRControl::processWakeup(const unsigned char* data)
|
||||||
{
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
// Wakeups always come in on slot 1
|
// Wakeups always come in on slot 1
|
||||||
if (data[0U] != TAG_DATA || data[1U] != (DMR_IDLE_RX | DMR_SYNC_DATA | DT_CSBK))
|
if (data[0U] != TAG_DATA || data[1U] != (DMR_IDLE_RX | DMR_SYNC_DATA | DT_CSBK))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
CCSBK csbk(data + 2U);
|
CDMRCSBK csbk;
|
||||||
|
bool valid = csbk.put(data + 2U);
|
||||||
|
if (!valid)
|
||||||
|
return false;
|
||||||
|
|
||||||
CSBKO csbko = csbk.getCSBKO();
|
CSBKO csbko = csbk.getCSBKO();
|
||||||
if (csbko != CSBKO_BSDWNACT)
|
if (csbko != CSBKO_BSDWNACT)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
unsigned int bsId = csbk.getBSId();
|
unsigned int srcId = csbk.getSrcId();
|
||||||
if (bsId == 0xFFFFFFU) {
|
std::string src = m_lookup->find(srcId);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
bool ret = CDMRAccessControl::validateSrcId(srcId);
|
||||||
|
if (!ret) {
|
||||||
|
LogMessage("Invalid Downlink Activate received from %s", src.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDMRControl::writeModemSlot1(unsigned char *data)
|
LogMessage("Downlink Activate received from %s", src.c_str());
|
||||||
{
|
|
||||||
m_slot1.writeModem(data);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDMRControl::writeModemSlot2(unsigned char *data)
|
bool CDMRControl::writeModemSlot1(unsigned char *data, unsigned int len)
|
||||||
{
|
{
|
||||||
m_slot2.writeModem(data);
|
assert(data != NULL);
|
||||||
|
|
||||||
|
return m_slot1.writeModem(data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMRControl::writeModemSlot2(unsigned char *data, unsigned int len)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
return m_slot2.writeModem(data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int CDMRControl::readModemSlot1(unsigned char *data)
|
unsigned int CDMRControl::readModemSlot1(unsigned char *data)
|
||||||
{
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
return m_slot1.readModem(data);
|
return m_slot1.readModem(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int CDMRControl::readModemSlot2(unsigned char *data)
|
unsigned int CDMRControl::readModemSlot2(unsigned char *data)
|
||||||
{
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
return m_slot2.readModem(data);
|
return m_slot2.readModem(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDMRControl::clock(unsigned int ms)
|
void CDMRControl::clock()
|
||||||
{
|
{
|
||||||
if (m_network != NULL) {
|
if (m_network != NULL) {
|
||||||
CDMRData data;
|
CDMRData data;
|
||||||
|
@ -93,10 +117,22 @@ void CDMRControl::clock(unsigned int ms)
|
||||||
default: LogError("Invalid slot no %u", slotNo); break;
|
default: LogError("Invalid slot no %u", slotNo); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_network->clock(ms);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_slot1.clock(ms);
|
m_slot1.clock();
|
||||||
m_slot2.clock(ms);
|
m_slot2.clock();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMRControl::isBusy() const
|
||||||
|
{
|
||||||
|
if (m_slot1.isBusy())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return m_slot2.isBusy();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMRControl::enable(bool enabled)
|
||||||
|
{
|
||||||
|
m_slot1.enable(enabled);
|
||||||
|
m_slot2.enable(enabled);
|
||||||
}
|
}
|
||||||
|
|
23
DMRControl.h
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015-2019 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -19,35 +19,42 @@
|
||||||
#if !defined(DMRControl_H)
|
#if !defined(DMRControl_H)
|
||||||
#define DMRControl_H
|
#define DMRControl_H
|
||||||
|
|
||||||
#include "HomebrewDMRIPSC.h"
|
#include "RSSIInterpolator.h"
|
||||||
|
#include "DMRNetwork.h"
|
||||||
|
#include "DMRLookup.h"
|
||||||
#include "Display.h"
|
#include "Display.h"
|
||||||
#include "DMRSlot.h"
|
#include "DMRSlot.h"
|
||||||
#include "DMRData.h"
|
#include "DMRData.h"
|
||||||
#include "Modem.h"
|
#include "Modem.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class CDMRControl {
|
class CDMRControl {
|
||||||
public:
|
public:
|
||||||
CDMRControl(unsigned int id, unsigned int colorCode, unsigned int timeout, CModem* modem, CHomebrewDMRIPSC* network, IDisplay* display);
|
CDMRControl(unsigned int id, unsigned int colorCode, unsigned int callHang, bool selfOnly, bool embeddedLCOnly, bool dumpTAData, const std::vector<unsigned int>& prefixes, const std::vector<unsigned int>& blacklist, const std::vector<unsigned int>& whitelist, const std::vector<unsigned int>& slot1TGWhitelist, const std::vector<unsigned int>& slot2TGWhitelist, unsigned int timeout, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssi, unsigned int jitter, DMR_OVCM_TYPES ovcm);
|
||||||
~CDMRControl();
|
~CDMRControl();
|
||||||
|
|
||||||
bool processWakeup(const unsigned char* data);
|
bool processWakeup(const unsigned char* data);
|
||||||
|
|
||||||
void writeModemSlot1(unsigned char* data);
|
bool writeModemSlot1(unsigned char* data, unsigned int len);
|
||||||
void writeModemSlot2(unsigned char* data);
|
bool writeModemSlot2(unsigned char* data, unsigned int len);
|
||||||
|
|
||||||
unsigned int readModemSlot1(unsigned char* data);
|
unsigned int readModemSlot1(unsigned char* data);
|
||||||
unsigned int readModemSlot2(unsigned char* data);
|
unsigned int readModemSlot2(unsigned char* data);
|
||||||
|
|
||||||
void clock(unsigned int ms);
|
void clock();
|
||||||
|
|
||||||
|
bool isBusy() const;
|
||||||
|
|
||||||
|
void enable(bool enabled);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned int m_id;
|
|
||||||
unsigned int m_colorCode;
|
unsigned int m_colorCode;
|
||||||
CModem* m_modem;
|
CModem* m_modem;
|
||||||
CHomebrewDMRIPSC* m_network;
|
CDMRNetwork* m_network;
|
||||||
CDMRSlot m_slot1;
|
CDMRSlot m_slot1;
|
||||||
CDMRSlot m_slot2;
|
CDMRSlot m_slot2;
|
||||||
|
CDMRLookup* m_lookup;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
32
DMRData.cpp
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 Jonathan Naylor, G4KLX
|
* Copyright (C) 2015,2016,2017 Jonathan Naylor, G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -29,7 +29,9 @@ m_dstId(data.m_dstId),
|
||||||
m_flco(data.m_flco),
|
m_flco(data.m_flco),
|
||||||
m_dataType(data.m_dataType),
|
m_dataType(data.m_dataType),
|
||||||
m_seqNo(data.m_seqNo),
|
m_seqNo(data.m_seqNo),
|
||||||
m_n(data.m_n)
|
m_n(data.m_n),
|
||||||
|
m_ber(data.m_ber),
|
||||||
|
m_rssi(data.m_rssi)
|
||||||
{
|
{
|
||||||
m_data = new unsigned char[2U * DMR_FRAME_LENGTH_BYTES];
|
m_data = new unsigned char[2U * DMR_FRAME_LENGTH_BYTES];
|
||||||
::memcpy(m_data, data.m_data, 2U * DMR_FRAME_LENGTH_BYTES);
|
::memcpy(m_data, data.m_data, 2U * DMR_FRAME_LENGTH_BYTES);
|
||||||
|
@ -43,7 +45,9 @@ m_dstId(0U),
|
||||||
m_flco(FLCO_GROUP),
|
m_flco(FLCO_GROUP),
|
||||||
m_dataType(0U),
|
m_dataType(0U),
|
||||||
m_seqNo(0U),
|
m_seqNo(0U),
|
||||||
m_n(0U)
|
m_n(0U),
|
||||||
|
m_ber(0U),
|
||||||
|
m_rssi(0U)
|
||||||
{
|
{
|
||||||
m_data = new unsigned char[2U * DMR_FRAME_LENGTH_BYTES];
|
m_data = new unsigned char[2U * DMR_FRAME_LENGTH_BYTES];
|
||||||
}
|
}
|
||||||
|
@ -65,6 +69,8 @@ CDMRData& CDMRData::operator=(const CDMRData& data)
|
||||||
m_dataType = data.m_dataType;
|
m_dataType = data.m_dataType;
|
||||||
m_seqNo = data.m_seqNo;
|
m_seqNo = data.m_seqNo;
|
||||||
m_n = data.m_n;
|
m_n = data.m_n;
|
||||||
|
m_ber = data.m_ber;
|
||||||
|
m_rssi = data.m_rssi;
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -142,6 +148,26 @@ void CDMRData::setN(unsigned char n)
|
||||||
m_n = n;
|
m_n = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned char CDMRData::getBER() const
|
||||||
|
{
|
||||||
|
return m_ber;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMRData::setBER(unsigned char ber)
|
||||||
|
{
|
||||||
|
m_ber = ber;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char CDMRData::getRSSI() const
|
||||||
|
{
|
||||||
|
return m_rssi;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMRData::setRSSI(unsigned char rssi)
|
||||||
|
{
|
||||||
|
m_rssi = rssi;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int CDMRData::getData(unsigned char* buffer) const
|
unsigned int CDMRData::getData(unsigned char* buffer) const
|
||||||
{
|
{
|
||||||
assert(buffer != NULL);
|
assert(buffer != NULL);
|
||||||
|
|
10
DMRData.h
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 by Jonathan Naylor, G4KLX
|
* Copyright (C) 2015,2016,2017 by Jonathan Naylor, G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -45,6 +45,12 @@ public:
|
||||||
unsigned char getDataType() const;
|
unsigned char getDataType() const;
|
||||||
void setDataType(unsigned char dataType);
|
void setDataType(unsigned char dataType);
|
||||||
|
|
||||||
|
unsigned char getBER() const;
|
||||||
|
void setBER(unsigned char ber);
|
||||||
|
|
||||||
|
unsigned char getRSSI() const;
|
||||||
|
void setRSSI(unsigned char rssi);
|
||||||
|
|
||||||
void setData(const unsigned char* buffer);
|
void setData(const unsigned char* buffer);
|
||||||
unsigned int getData(unsigned char* buffer) const;
|
unsigned int getData(unsigned char* buffer) const;
|
||||||
|
|
||||||
|
@ -57,6 +63,8 @@ private:
|
||||||
unsigned char m_dataType;
|
unsigned char m_dataType;
|
||||||
unsigned char m_seqNo;
|
unsigned char m_seqNo;
|
||||||
unsigned char m_n;
|
unsigned char m_n;
|
||||||
|
unsigned char m_ber;
|
||||||
|
unsigned char m_rssi;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
175
DMRDataHeader.cpp
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2012 by Ian Wraith
|
||||||
|
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "DMRDataHeader.h"
|
||||||
|
#include "DMRDefines.h"
|
||||||
|
#include "BPTC19696.h"
|
||||||
|
#include "RS129.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
#include "CRC.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
const unsigned char UDTF_NMEA = 0x05U;
|
||||||
|
|
||||||
|
CDMRDataHeader::CDMRDataHeader() :
|
||||||
|
m_data(NULL),
|
||||||
|
m_GI(false),
|
||||||
|
m_A(false),
|
||||||
|
m_srcId(0U),
|
||||||
|
m_dstId(0U),
|
||||||
|
m_blocks(0U),
|
||||||
|
m_F(false),
|
||||||
|
m_S(false),
|
||||||
|
m_Ns(0U)
|
||||||
|
{
|
||||||
|
m_data = new unsigned char[12U];
|
||||||
|
}
|
||||||
|
|
||||||
|
CDMRDataHeader::~CDMRDataHeader()
|
||||||
|
{
|
||||||
|
delete[] m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMRDataHeader::put(const unsigned char* bytes)
|
||||||
|
{
|
||||||
|
assert(bytes != NULL);
|
||||||
|
|
||||||
|
CBPTC19696 bptc;
|
||||||
|
bptc.decode(bytes, m_data);
|
||||||
|
|
||||||
|
m_data[10U] ^= DATA_HEADER_CRC_MASK[0U];
|
||||||
|
m_data[11U] ^= DATA_HEADER_CRC_MASK[1U];
|
||||||
|
|
||||||
|
bool valid = CCRC::checkCCITT162(m_data, 12U);
|
||||||
|
if (!valid)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Restore the checksum
|
||||||
|
m_data[10U] ^= DATA_HEADER_CRC_MASK[0U];
|
||||||
|
m_data[11U] ^= DATA_HEADER_CRC_MASK[1U];
|
||||||
|
|
||||||
|
m_GI = (m_data[0U] & 0x80U) == 0x80U;
|
||||||
|
m_A = (m_data[0U] & 0x40U) == 0x40U;
|
||||||
|
|
||||||
|
unsigned char dpf = m_data[0U] & 0x0FU;
|
||||||
|
if (dpf == DPF_PROPRIETARY)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
m_dstId = m_data[2U] << 16 | m_data[3U] << 8 | m_data[4U];
|
||||||
|
m_srcId = m_data[5U] << 16 | m_data[6U] << 8 | m_data[7U];
|
||||||
|
|
||||||
|
switch (dpf) {
|
||||||
|
case DPF_UNCONFIRMED_DATA:
|
||||||
|
CUtils::dump(1U, "DMR, Unconfirmed Data Header", m_data, 12U);
|
||||||
|
m_F = (m_data[8U] & 0x80U) == 0x80U;
|
||||||
|
m_blocks = m_data[8U] & 0x7FU;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DPF_CONFIRMED_DATA:
|
||||||
|
CUtils::dump(1U, "DMR, Confirmed Data Header", m_data, 12U);
|
||||||
|
m_F = (m_data[8U] & 0x80U) == 0x80U;
|
||||||
|
m_blocks = m_data[8U] & 0x7FU;
|
||||||
|
m_S = (m_data[9U] & 0x80U) == 0x80U;
|
||||||
|
m_Ns = (m_data[9U] >> 4) & 0x07U;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DPF_RESPONSE:
|
||||||
|
CUtils::dump(1U, "DMR, Response Data Header", m_data, 12U);
|
||||||
|
m_blocks = m_data[8U] & 0x7FU;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DPF_PROPRIETARY:
|
||||||
|
CUtils::dump(1U, "DMR, Proprietary Data Header", m_data, 12U);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DPF_DEFINED_RAW:
|
||||||
|
CUtils::dump(1U, "DMR, Raw or Status/Precoded Short Data Header", m_data, 12U);
|
||||||
|
m_blocks = (m_data[0U] & 0x30U) + (m_data[1U] & 0x0FU);
|
||||||
|
m_F = (m_data[8U] & 0x01U) == 0x01U;
|
||||||
|
m_S = (m_data[8U] & 0x02U) == 0x02U;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DPF_DEFINED_SHORT:
|
||||||
|
CUtils::dump(1U, "DMR, Defined Short Data Header", m_data, 12U);
|
||||||
|
m_blocks = (m_data[0U] & 0x30U) + (m_data[1U] & 0x0FU);
|
||||||
|
m_F = (m_data[8U] & 0x01U) == 0x01U;
|
||||||
|
m_S = (m_data[8U] & 0x02U) == 0x02U;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DPF_UDT:
|
||||||
|
CUtils::dump(1U, "DMR, Unified Data Transport Header", m_data, 12U);
|
||||||
|
m_blocks = (m_data[8U] & 0x03U) + 1U;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
CUtils::dump("DMR, Unknown Data Header", m_data, 12U);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMRDataHeader::get(unsigned char* bytes) const
|
||||||
|
{
|
||||||
|
assert(bytes != NULL);
|
||||||
|
|
||||||
|
CBPTC19696 bptc;
|
||||||
|
bptc.encode(m_data, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMRDataHeader::getGI() const
|
||||||
|
{
|
||||||
|
return m_GI;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CDMRDataHeader::getSrcId() const
|
||||||
|
{
|
||||||
|
return m_srcId;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CDMRDataHeader::getDstId() const
|
||||||
|
{
|
||||||
|
return m_dstId;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CDMRDataHeader::getBlocks() const
|
||||||
|
{
|
||||||
|
return m_blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
CDMRDataHeader& CDMRDataHeader::operator=(const CDMRDataHeader& header)
|
||||||
|
{
|
||||||
|
if (&header != this) {
|
||||||
|
::memcpy(m_data, header.m_data, 12U);
|
||||||
|
m_GI = header.m_GI;
|
||||||
|
m_A = header.m_A;
|
||||||
|
m_srcId = header.m_srcId;
|
||||||
|
m_dstId = header.m_dstId;
|
||||||
|
m_blocks = header.m_blocks;
|
||||||
|
m_F = header.m_F;
|
||||||
|
m_S = header.m_S;
|
||||||
|
m_Ns = header.m_Ns;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,43 +16,39 @@
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if !defined(CSBK_H)
|
#ifndef DMRDataHeader_H
|
||||||
#define CSBK_H
|
#define DMRDataHeader_H
|
||||||
|
|
||||||
#include "DMRDefines.h"
|
class CDMRDataHeader
|
||||||
|
|
||||||
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:
|
public:
|
||||||
CCSBK(const unsigned char* bytes);
|
CDMRDataHeader();
|
||||||
~CCSBK();
|
~CDMRDataHeader();
|
||||||
|
|
||||||
bool isValid() const;
|
bool put(const unsigned char* bytes);
|
||||||
|
|
||||||
// Generic fields
|
void get(unsigned char* bytes) const;
|
||||||
CSBKO getCSBKO() const;
|
|
||||||
unsigned char getFID() const;
|
bool getGI() const;
|
||||||
|
|
||||||
// For BS Dwn Act
|
|
||||||
unsigned int getBSId() const;
|
|
||||||
unsigned int getSrcId() const;
|
unsigned int getSrcId() const;
|
||||||
|
unsigned int getDstId() const;
|
||||||
|
|
||||||
|
unsigned int getBlocks() const;
|
||||||
|
|
||||||
|
CDMRDataHeader& operator=(const CDMRDataHeader& header);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CSBKO m_CSBKO;
|
unsigned char* m_data;
|
||||||
unsigned char m_FID;
|
bool m_GI;
|
||||||
unsigned int m_bsId;
|
bool m_A;
|
||||||
unsigned int m_srcId;
|
unsigned int m_srcId;
|
||||||
bool m_valid;
|
unsigned int m_dstId;
|
||||||
|
unsigned int m_blocks;
|
||||||
|
bool m_F;
|
||||||
|
bool m_S;
|
||||||
|
unsigned char m_Ns;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
32
DMRDefines.h
|
@ -19,6 +19,8 @@
|
||||||
#if !defined(DMRDefines_H)
|
#if !defined(DMRDefines_H)
|
||||||
#define DMRDefines_H
|
#define DMRDefines_H
|
||||||
|
|
||||||
|
#include "Defines.h" // For TAG_DATA
|
||||||
|
|
||||||
const unsigned int DMR_FRAME_LENGTH_BITS = 264U;
|
const unsigned int DMR_FRAME_LENGTH_BITS = 264U;
|
||||||
const unsigned int DMR_FRAME_LENGTH_BYTES = 33U;
|
const unsigned int DMR_FRAME_LENGTH_BYTES = 33U;
|
||||||
|
|
||||||
|
@ -52,16 +54,24 @@ const unsigned char DIRECT_SLOT2_DATA_SYNC[] = {0x0DU, 0x75U, 0x57U, 0xF5U, 0xF
|
||||||
const unsigned char SYNC_MASK[] = {0x0FU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xF0U};
|
const unsigned char SYNC_MASK[] = {0x0FU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xF0U};
|
||||||
|
|
||||||
// The PR FILL and Data Sync pattern.
|
// The PR FILL and Data Sync pattern.
|
||||||
const unsigned char IDLE_DATA[] =
|
const unsigned char DMR_IDLE_DATA[] = {TAG_DATA, 0x00U,
|
||||||
{0x53U, 0xC2U, 0x5EU, 0xABU, 0xA8U, 0x67U, 0x1DU, 0xC7U, 0x38U, 0x3BU, 0xD9U,
|
0x53U, 0xC2U, 0x5EU, 0xABU, 0xA8U, 0x67U, 0x1DU, 0xC7U, 0x38U, 0x3BU, 0xD9U,
|
||||||
0x36U, 0x00U, 0x0DU, 0xFFU, 0x57U, 0xD7U, 0x5DU, 0xF5U, 0xD0U, 0x03U, 0xF6U,
|
0x36U, 0x00U, 0x0DU, 0xFFU, 0x57U, 0xD7U, 0x5DU, 0xF5U, 0xD0U, 0x03U, 0xF6U,
|
||||||
0xE4U, 0x65U, 0x17U, 0x1BU, 0x48U, 0xCAU, 0x6DU, 0x4FU, 0xC6U, 0x10U, 0xB4U};
|
0xE4U, 0x65U, 0x17U, 0x1BU, 0x48U, 0xCAU, 0x6DU, 0x4FU, 0xC6U, 0x10U, 0xB4U};
|
||||||
|
|
||||||
|
// A silence frame only
|
||||||
|
const unsigned char DMR_SILENCE_DATA[] = {TAG_DATA, 0x00U,
|
||||||
|
0xB9U, 0xE8U, 0x81U, 0x52U, 0x61U, 0x73U, 0x00U, 0x2AU, 0x6BU, 0xB9U, 0xE8U,
|
||||||
|
0x81U, 0x52U, 0x60U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x01U, 0x73U, 0x00U,
|
||||||
|
0x2AU, 0x6BU, 0xB9U, 0xE8U, 0x81U, 0x52U, 0x61U, 0x73U, 0x00U, 0x2AU, 0x6BU};
|
||||||
|
|
||||||
const unsigned char PAYLOAD_LEFT_MASK[] = {0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xF0U};
|
const unsigned char PAYLOAD_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 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 VOICE_LC_HEADER_CRC_MASK[] = {0x96U, 0x96U, 0x96U};
|
||||||
const unsigned char TERMINATOR_WITH_LC_CRC_MASK[] = {0x99U, 0x99U, 0x99U};
|
const unsigned char TERMINATOR_WITH_LC_CRC_MASK[] = {0x99U, 0x99U, 0x99U};
|
||||||
|
const unsigned char PI_HEADER_CRC_MASK[] = {0x69U, 0x69U};
|
||||||
|
const unsigned char DATA_HEADER_CRC_MASK[] = {0xCCU, 0xCCU};
|
||||||
const unsigned char CSBK_CRC_MASK[] = {0xA5U, 0xA5U};
|
const unsigned char CSBK_CRC_MASK[] = {0xA5U, 0xA5U};
|
||||||
|
|
||||||
const unsigned int DMR_SLOT_TIME = 60U;
|
const unsigned int DMR_SLOT_TIME = 60U;
|
||||||
|
@ -73,7 +83,10 @@ const unsigned char DT_VOICE_LC_HEADER = 0x01U;
|
||||||
const unsigned char DT_TERMINATOR_WITH_LC = 0x02U;
|
const unsigned char DT_TERMINATOR_WITH_LC = 0x02U;
|
||||||
const unsigned char DT_CSBK = 0x03U;
|
const unsigned char DT_CSBK = 0x03U;
|
||||||
const unsigned char DT_DATA_HEADER = 0x06U;
|
const unsigned char DT_DATA_HEADER = 0x06U;
|
||||||
|
const unsigned char DT_RATE_12_DATA = 0x07U;
|
||||||
|
const unsigned char DT_RATE_34_DATA = 0x08U;
|
||||||
const unsigned char DT_IDLE = 0x09U;
|
const unsigned char DT_IDLE = 0x09U;
|
||||||
|
const unsigned char DT_RATE_1_DATA = 0x0AU;
|
||||||
|
|
||||||
// Dummy values
|
// Dummy values
|
||||||
const unsigned char DT_VOICE_SYNC = 0xF0U;
|
const unsigned char DT_VOICE_SYNC = 0xF0U;
|
||||||
|
@ -86,12 +99,25 @@ const unsigned char DMR_SYNC_AUDIO = 0x20U;
|
||||||
const unsigned char DMR_SLOT1 = 0x00U;
|
const unsigned char DMR_SLOT1 = 0x00U;
|
||||||
const unsigned char DMR_SLOT2 = 0x80U;
|
const unsigned char DMR_SLOT2 = 0x80U;
|
||||||
|
|
||||||
|
const unsigned char DPF_UDT = 0x00U;
|
||||||
|
const unsigned char DPF_RESPONSE = 0x01U;
|
||||||
|
const unsigned char DPF_UNCONFIRMED_DATA = 0x02U;
|
||||||
|
const unsigned char DPF_CONFIRMED_DATA = 0x03U;
|
||||||
|
const unsigned char DPF_DEFINED_SHORT = 0x0DU;
|
||||||
|
const unsigned char DPF_DEFINED_RAW = 0x0EU;
|
||||||
|
const unsigned char DPF_PROPRIETARY = 0x0FU;
|
||||||
|
|
||||||
const unsigned char FID_ETSI = 0U;
|
const unsigned char FID_ETSI = 0U;
|
||||||
const unsigned char FID_DMRA = 16U;
|
const unsigned char FID_DMRA = 16U;
|
||||||
|
|
||||||
enum FLCO {
|
enum FLCO {
|
||||||
FLCO_GROUP = 0,
|
FLCO_GROUP = 0,
|
||||||
FLCO_USER_USER = 3
|
FLCO_USER_USER = 3,
|
||||||
|
FLCO_TALKER_ALIAS_HEADER = 4,
|
||||||
|
FLCO_TALKER_ALIAS_BLOCK1 = 5,
|
||||||
|
FLCO_TALKER_ALIAS_BLOCK2 = 6,
|
||||||
|
FLCO_TALKER_ALIAS_BLOCK3 = 7,
|
||||||
|
FLCO_GPS_INFO = 8
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
100
DMREMB.cpp
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "DMREMB.h"
|
||||||
|
|
||||||
|
#include "QR1676.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
CDMREMB::CDMREMB() :
|
||||||
|
m_colorCode(0U),
|
||||||
|
m_PI(false),
|
||||||
|
m_LCSS(0U)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CDMREMB::~CDMREMB()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMREMB::putData(const unsigned char* data)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
unsigned char DMREMB[2U];
|
||||||
|
DMREMB[0U] = (data[13U] << 4) & 0xF0U;
|
||||||
|
DMREMB[0U] |= (data[14U] >> 4) & 0x0FU;
|
||||||
|
DMREMB[1U] = (data[18U] << 4) & 0xF0U;
|
||||||
|
DMREMB[1U] |= (data[19U] >> 4) & 0x0FU;
|
||||||
|
|
||||||
|
unsigned char code = CQR1676::decode(DMREMB);
|
||||||
|
|
||||||
|
m_colorCode = (code >> 4) & 0x0FU;
|
||||||
|
m_PI = (code & 0x08U) == 0x08U;
|
||||||
|
m_LCSS = (code >> 1) & 0x03U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMREMB::getData(unsigned char* data) const
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
unsigned char DMREMB[2U];
|
||||||
|
DMREMB[0U] = (m_colorCode << 4) & 0xF0U;
|
||||||
|
DMREMB[0U] |= m_PI ? 0x08U : 0x00U;
|
||||||
|
DMREMB[0U] |= (m_LCSS << 1) & 0x06U;
|
||||||
|
DMREMB[1U] = 0x00U;
|
||||||
|
|
||||||
|
CQR1676::encode(DMREMB);
|
||||||
|
|
||||||
|
data[13U] = (data[13U] & 0xF0U) | ((DMREMB[0U] >> 4U) & 0x0FU);
|
||||||
|
data[14U] = (data[14U] & 0x0FU) | ((DMREMB[0U] << 4U) & 0xF0U);
|
||||||
|
data[18U] = (data[18U] & 0xF0U) | ((DMREMB[1U] >> 4U) & 0x0FU);
|
||||||
|
data[19U] = (data[19U] & 0x0FU) | ((DMREMB[1U] << 4U) & 0xF0U);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char CDMREMB::getColorCode() const
|
||||||
|
{
|
||||||
|
return m_colorCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMREMB::setColorCode(unsigned char code)
|
||||||
|
{
|
||||||
|
m_colorCode = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMREMB::getPI() const
|
||||||
|
{
|
||||||
|
return m_PI;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMREMB::setPI(bool pi)
|
||||||
|
{
|
||||||
|
m_PI = pi;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char CDMREMB::getLCSS() const
|
||||||
|
{
|
||||||
|
return m_LCSS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMREMB::setLCSS(unsigned char lcss)
|
||||||
|
{
|
||||||
|
m_LCSS = lcss;
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,14 +16,14 @@
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if !defined(EMB_H)
|
#if !defined(DMREMB_H)
|
||||||
#define EMB_H
|
#define DMREMB_H
|
||||||
|
|
||||||
class CEMB
|
class CDMREMB
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CEMB();
|
CDMREMB();
|
||||||
~CEMB();
|
~CDMREMB();
|
||||||
|
|
||||||
void putData(const unsigned char* data);
|
void putData(const unsigned char* data);
|
||||||
void getData(unsigned char* data) const;
|
void getData(unsigned char* data) const;
|
||||||
|
@ -44,4 +44,3 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,31 +16,35 @@
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "EmbeddedLC.h"
|
#include "DMREmbeddedData.h"
|
||||||
|
|
||||||
#include "Hamming.h"
|
#include "Hamming.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
#include "CRC.h"
|
#include "CRC.h"
|
||||||
#include "Log.h"
|
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
CEmbeddedLC::CEmbeddedLC() :
|
CDMREmbeddedData::CDMREmbeddedData() :
|
||||||
m_rawLC(NULL),
|
m_raw(NULL),
|
||||||
m_state(LCS_NONE)
|
m_state(LCS_NONE),
|
||||||
|
m_data(NULL),
|
||||||
|
m_FLCO(FLCO_GROUP),
|
||||||
|
m_valid(false)
|
||||||
{
|
{
|
||||||
m_rawLC = new bool[128U];
|
m_raw = new bool[128U];
|
||||||
|
m_data = new bool[72U];
|
||||||
}
|
}
|
||||||
|
|
||||||
CEmbeddedLC::~CEmbeddedLC()
|
CDMREmbeddedData::~CDMREmbeddedData()
|
||||||
{
|
{
|
||||||
delete[] m_rawLC;
|
delete[] m_raw;
|
||||||
|
delete[] m_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add LC data (which may consist of 4 blocks) to the data store
|
// Add LC data (which may consist of 4 blocks) to the data store
|
||||||
CLC* CEmbeddedLC::addData(const unsigned char* data, unsigned char lcss)
|
bool CDMREmbeddedData::addData(const unsigned char* data, unsigned char lcss)
|
||||||
{
|
{
|
||||||
assert(data != NULL);
|
assert(data != NULL);
|
||||||
|
|
||||||
|
@ -54,58 +58,70 @@ CLC* CEmbeddedLC::addData(const unsigned char* data, unsigned char lcss)
|
||||||
// Is this the first block of a 4 block embedded LC ?
|
// Is this the first block of a 4 block embedded LC ?
|
||||||
if (lcss == 1U) {
|
if (lcss == 1U) {
|
||||||
for (unsigned int a = 0U; a < 32U; a++)
|
for (unsigned int a = 0U; a < 32U; a++)
|
||||||
m_rawLC[a] = rawData[a + 4U];
|
m_raw[a] = rawData[a + 4U];
|
||||||
|
|
||||||
// Show we are ready for the next LC block
|
// Show we are ready for the next LC block
|
||||||
m_state = LCS_FIRST;
|
m_state = LCS_FIRST;
|
||||||
return NULL;
|
m_valid = false;
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is this the 2nd block of a 4 block embedded LC ?
|
// Is this the 2nd block of a 4 block embedded LC ?
|
||||||
if (lcss == 3U && m_state == LCS_FIRST) {
|
if (lcss == 3U && m_state == LCS_FIRST) {
|
||||||
for (unsigned int a = 0U; a < 32U; a++)
|
for (unsigned int a = 0U; a < 32U; a++)
|
||||||
m_rawLC[a + 32U] = rawData[a + 4U];
|
m_raw[a + 32U] = rawData[a + 4U];
|
||||||
|
|
||||||
// Show we are ready for the next LC block
|
// Show we are ready for the next LC block
|
||||||
m_state = LCS_SECOND;
|
m_state = LCS_SECOND;
|
||||||
return NULL;
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is this the 3rd block of a 4 block embedded LC ?
|
// Is this the 3rd block of a 4 block embedded LC ?
|
||||||
if (lcss == 3U && m_state == LCS_SECOND) {
|
if (lcss == 3U && m_state == LCS_SECOND) {
|
||||||
for (unsigned int a = 0U; a < 32U; a++)
|
for (unsigned int a = 0U; a < 32U; a++)
|
||||||
m_rawLC[a + 64U] = rawData[a + 4U];
|
m_raw[a + 64U] = rawData[a + 4U];
|
||||||
|
|
||||||
// Show we are ready for the final LC block
|
// Show we are ready for the final LC block
|
||||||
m_state = LCS_THIRD;
|
m_state = LCS_THIRD;
|
||||||
return NULL;
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is this the final block of a 4 block embedded LC ?
|
// Is this the final block of a 4 block embedded LC ?
|
||||||
if (lcss == 2U && m_state == LCS_THIRD) {
|
if (lcss == 2U && m_state == LCS_THIRD) {
|
||||||
for (unsigned int a = 0U; a < 32U; a++)
|
for (unsigned int a = 0U; a < 32U; a++)
|
||||||
m_rawLC[a + 96U] = rawData[a + 4U];
|
m_raw[a + 96U] = rawData[a + 4U];
|
||||||
|
|
||||||
|
// Show that we're not ready for any more data
|
||||||
|
m_state = LCS_NONE;
|
||||||
|
|
||||||
// Process the complete data block
|
// Process the complete data block
|
||||||
return processMultiBlockEmbeddedLC();
|
decodeEmbeddedData();
|
||||||
|
if (m_valid)
|
||||||
|
encodeEmbeddedData();
|
||||||
|
|
||||||
|
return m_valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is this a single block embedded LC
|
return false;
|
||||||
if (lcss == 0U) {
|
|
||||||
processSingleBlockEmbeddedLC(rawData + 4U);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
void CDMREmbeddedData::setLC(const CDMRLC& lc)
|
||||||
}
|
|
||||||
|
|
||||||
void CEmbeddedLC::setData(const CLC& lc)
|
|
||||||
{
|
{
|
||||||
bool lcData[72U];
|
lc.getData(m_data);
|
||||||
lc.getData(lcData);
|
|
||||||
|
|
||||||
|
m_FLCO = lc.getFLCO();
|
||||||
|
m_valid = true;
|
||||||
|
|
||||||
|
encodeEmbeddedData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMREmbeddedData::encodeEmbeddedData()
|
||||||
|
{
|
||||||
unsigned int crc;
|
unsigned int crc;
|
||||||
CCRC::encodeFiveBit(lcData, crc);
|
CCRC::encodeFiveBit(m_data, crc);
|
||||||
|
|
||||||
bool data[128U];
|
bool data[128U];
|
||||||
::memset(data, 0x00U, 128U * sizeof(bool));
|
::memset(data, 0x00U, 128U * sizeof(bool));
|
||||||
|
@ -118,19 +134,19 @@ void CEmbeddedLC::setData(const CLC& lc)
|
||||||
|
|
||||||
unsigned int b = 0U;
|
unsigned int b = 0U;
|
||||||
for (unsigned int a = 0U; a < 11U; a++, b++)
|
for (unsigned int a = 0U; a < 11U; a++, b++)
|
||||||
data[a] = lcData[b];
|
data[a] = m_data[b];
|
||||||
for (unsigned int a = 16U; a < 27U; a++, b++)
|
for (unsigned int a = 16U; a < 27U; a++, b++)
|
||||||
data[a] = lcData[b];
|
data[a] = m_data[b];
|
||||||
for (unsigned int a = 32U; a < 42U; a++, b++)
|
for (unsigned int a = 32U; a < 42U; a++, b++)
|
||||||
data[a] = lcData[b];
|
data[a] = m_data[b];
|
||||||
for (unsigned int a = 48U; a < 58U; a++, b++)
|
for (unsigned int a = 48U; a < 58U; a++, b++)
|
||||||
data[a] = lcData[b];
|
data[a] = m_data[b];
|
||||||
for (unsigned int a = 64U; a < 74U; a++, b++)
|
for (unsigned int a = 64U; a < 74U; a++, b++)
|
||||||
data[a] = lcData[b];
|
data[a] = m_data[b];
|
||||||
for (unsigned int a = 80U; a < 90U; a++, b++)
|
for (unsigned int a = 80U; a < 90U; a++, b++)
|
||||||
data[a] = lcData[b];
|
data[a] = m_data[b];
|
||||||
for (unsigned int a = 96U; a < 106U; a++, b++)
|
for (unsigned int a = 96U; a < 106U; a++, b++)
|
||||||
data[a] = lcData[b];
|
data[a] = m_data[b];
|
||||||
|
|
||||||
// Hamming (16,11,4) check each row except the last one
|
// Hamming (16,11,4) check each row except the last one
|
||||||
for (unsigned int a = 0U; a < 112U; a += 16U)
|
for (unsigned int a = 0U; a < 112U; a += 16U)
|
||||||
|
@ -143,21 +159,23 @@ void CEmbeddedLC::setData(const CLC& lc)
|
||||||
// The data is packed downwards in columns
|
// The data is packed downwards in columns
|
||||||
b = 0U;
|
b = 0U;
|
||||||
for (unsigned int a = 0U; a < 128U; a++) {
|
for (unsigned int a = 0U; a < 128U; a++) {
|
||||||
m_rawLC[a] = data[b];
|
m_raw[a] = data[b];
|
||||||
b += 16U;
|
b += 16U;
|
||||||
if (b > 127U)
|
if (b > 127U)
|
||||||
b -= 127U;
|
b -= 127U;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int CEmbeddedLC::getData(unsigned char* data, unsigned int n) const
|
unsigned char CDMREmbeddedData::getData(unsigned char* data, unsigned char n) const
|
||||||
{
|
{
|
||||||
assert(data != NULL);
|
assert(data != NULL);
|
||||||
|
|
||||||
if (n < 4U) {
|
if (n >= 1U && n < 5U) {
|
||||||
|
n--;
|
||||||
|
|
||||||
bool bits[40U];
|
bool bits[40U];
|
||||||
::memset(bits, 0x00U, 40U * sizeof(bool));
|
::memset(bits, 0x00U, 40U * sizeof(bool));
|
||||||
::memcpy(bits + 4U, m_rawLC + n * 32U, 32U * sizeof(bool));
|
::memcpy(bits + 4U, m_raw + n * 32U, 32U * sizeof(bool));
|
||||||
|
|
||||||
unsigned char bytes[5U];
|
unsigned char bytes[5U];
|
||||||
CUtils::bitsToByteBE(bits + 0U, bytes[0U]);
|
CUtils::bitsToByteBE(bits + 0U, bytes[0U]);
|
||||||
|
@ -171,29 +189,28 @@ unsigned int CEmbeddedLC::getData(unsigned char* data, unsigned int n) const
|
||||||
data[16U] = bytes[2U];
|
data[16U] = bytes[2U];
|
||||||
data[17U] = bytes[3U];
|
data[17U] = bytes[3U];
|
||||||
data[18U] = (data[18U] & 0x0FU) | (bytes[4U] & 0xF0U);
|
data[18U] = (data[18U] & 0x0FU) | (bytes[4U] & 0xF0U);
|
||||||
|
|
||||||
|
switch (n) {
|
||||||
|
case 0U:
|
||||||
|
return 1U;
|
||||||
|
case 3U:
|
||||||
|
return 2U;
|
||||||
|
default:
|
||||||
|
return 3U;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
data[14U] &= 0xF0U;
|
data[14U] &= 0xF0U;
|
||||||
data[15U] = 0x00U;
|
data[15U] = 0x00U;
|
||||||
data[16U] = 0x00U;
|
data[16U] = 0x00U;
|
||||||
data[17U] = 0x00U;
|
data[17U] = 0x00U;
|
||||||
data[18U] &= 0x0FU;
|
data[18U] &= 0x0FU;
|
||||||
}
|
|
||||||
|
|
||||||
switch (n) {
|
|
||||||
case 0U:
|
|
||||||
return 1U;
|
|
||||||
case 1U:
|
|
||||||
case 2U:
|
|
||||||
return 3U;
|
|
||||||
case 3U:
|
|
||||||
return 2U;
|
|
||||||
default:
|
|
||||||
return 0U;
|
return 0U;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unpack and error check an embedded LC
|
// Unpack and error check an embedded LC
|
||||||
CLC* CEmbeddedLC::processMultiBlockEmbeddedLC()
|
void CDMREmbeddedData::decodeEmbeddedData()
|
||||||
{
|
{
|
||||||
// The data is unpacked downwards in columns
|
// The data is unpacked downwards in columns
|
||||||
bool data[128U];
|
bool data[128U];
|
||||||
|
@ -201,7 +218,7 @@ CLC* CEmbeddedLC::processMultiBlockEmbeddedLC()
|
||||||
|
|
||||||
unsigned int b = 0U;
|
unsigned int b = 0U;
|
||||||
for (unsigned int a = 0U; a < 128U; a++) {
|
for (unsigned int a = 0U; a < 128U; a++) {
|
||||||
data[b] = m_rawLC[a];
|
data[b] = m_raw[a];
|
||||||
b += 16U;
|
b += 16U;
|
||||||
if (b > 127U)
|
if (b > 127U)
|
||||||
b -= 127U;
|
b -= 127U;
|
||||||
|
@ -209,38 +226,33 @@ CLC* CEmbeddedLC::processMultiBlockEmbeddedLC()
|
||||||
|
|
||||||
// Hamming (16,11,4) check each row except the last one
|
// Hamming (16,11,4) check each row except the last one
|
||||||
for (unsigned int a = 0U; a < 112U; a += 16U) {
|
for (unsigned int a = 0U; a < 112U; a += 16U) {
|
||||||
if (!CHamming::decode16114(data + a)) {
|
if (!CHamming::decode16114(data + a))
|
||||||
::LogDebug("Hamming decode of a row of the Embedded LC failed");
|
return;
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the parity bits
|
// Check the parity bits
|
||||||
for (unsigned int a = 0U; a < 16U; a++) {
|
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];
|
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) {
|
if (parity)
|
||||||
::LogDebug("Parity check of a column of the Embedded LC failed");
|
return;
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have passed the Hamming check so extract the actual payload
|
// We have passed the Hamming check so extract the actual payload
|
||||||
bool lcData[72U];
|
|
||||||
b = 0U;
|
b = 0U;
|
||||||
for (unsigned int a = 0U; a < 11U; a++, b++)
|
for (unsigned int a = 0U; a < 11U; a++, b++)
|
||||||
lcData[b] = data[a];
|
m_data[b] = data[a];
|
||||||
for (unsigned int a = 16U; a < 27U; a++, b++)
|
for (unsigned int a = 16U; a < 27U; a++, b++)
|
||||||
lcData[b] = data[a];
|
m_data[b] = data[a];
|
||||||
for (unsigned int a = 32U; a < 42U; a++, b++)
|
for (unsigned int a = 32U; a < 42U; a++, b++)
|
||||||
lcData[b] = data[a];
|
m_data[b] = data[a];
|
||||||
for (unsigned int a = 48U; a < 58U; a++, b++)
|
for (unsigned int a = 48U; a < 58U; a++, b++)
|
||||||
lcData[b] = data[a];
|
m_data[b] = data[a];
|
||||||
for (unsigned int a = 64U; a < 74U; a++, b++)
|
for (unsigned int a = 64U; a < 74U; a++, b++)
|
||||||
lcData[b] = data[a];
|
m_data[b] = data[a];
|
||||||
for (unsigned int a = 80U; a < 90U; a++, b++)
|
for (unsigned int a = 80U; a < 90U; a++, b++)
|
||||||
lcData[b] = data[a];
|
m_data[b] = data[a];
|
||||||
for (unsigned int a = 96U; a < 106U; a++, b++)
|
for (unsigned int a = 96U; a < 106U; a++, b++)
|
||||||
lcData[b] = data[a];
|
m_data[b] = data[a];
|
||||||
|
|
||||||
// Extract the 5 bit CRC
|
// Extract the 5 bit CRC
|
||||||
unsigned int crc = 0U;
|
unsigned int crc = 0U;
|
||||||
|
@ -251,16 +263,60 @@ CLC* CEmbeddedLC::processMultiBlockEmbeddedLC()
|
||||||
if (data[106]) crc += 1U;
|
if (data[106]) crc += 1U;
|
||||||
|
|
||||||
// Now CRC check this
|
// Now CRC check this
|
||||||
if (!CCRC::checkFiveBit(lcData, crc)) {
|
if (!CCRC::checkFiveBit(m_data, crc))
|
||||||
::LogDebug("Checksum of the Embedded LC failed");
|
return;
|
||||||
return NULL;
|
|
||||||
|
m_valid = true;
|
||||||
|
|
||||||
|
// Extract the FLCO
|
||||||
|
unsigned char flco;
|
||||||
|
CUtils::bitsToByteBE(m_data + 0U, flco);
|
||||||
|
m_FLCO = FLCO(flco & 0x3FU);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new CLC(lcData);
|
CDMRLC* CDMREmbeddedData::getLC() const
|
||||||
}
|
|
||||||
|
|
||||||
// Deal with a single block embedded LC
|
|
||||||
void CEmbeddedLC::processSingleBlockEmbeddedLC(const bool* data)
|
|
||||||
{
|
{
|
||||||
// Nothing interesting, or just NULL (I think)
|
if (!m_valid)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (m_FLCO != FLCO_GROUP && m_FLCO != FLCO_USER_USER)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return new CDMRLC(m_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMREmbeddedData::isValid() const
|
||||||
|
{
|
||||||
|
return m_valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
FLCO CDMREmbeddedData::getFLCO() const
|
||||||
|
{
|
||||||
|
return m_FLCO;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMREmbeddedData::reset()
|
||||||
|
{
|
||||||
|
m_state = LCS_NONE;
|
||||||
|
m_valid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMREmbeddedData::getRawData(unsigned char* data) const
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
if (!m_valid)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
CUtils::bitsToByteBE(m_data + 0U, data[0U]);
|
||||||
|
CUtils::bitsToByteBE(m_data + 8U, data[1U]);
|
||||||
|
CUtils::bitsToByteBE(m_data + 16U, data[2U]);
|
||||||
|
CUtils::bitsToByteBE(m_data + 24U, data[3U]);
|
||||||
|
CUtils::bitsToByteBE(m_data + 32U, data[4U]);
|
||||||
|
CUtils::bitsToByteBE(m_data + 40U, data[5U]);
|
||||||
|
CUtils::bitsToByteBE(m_data + 48U, data[6U]);
|
||||||
|
CUtils::bitsToByteBE(m_data + 56U, data[7U]);
|
||||||
|
CUtils::bitsToByteBE(m_data + 64U, data[8U]);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
63
DMREmbeddedData.h
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DMREmbeddedData_H
|
||||||
|
#define DMREmbeddedData_H
|
||||||
|
|
||||||
|
#include "DMRDefines.h"
|
||||||
|
#include "DMRLC.h"
|
||||||
|
|
||||||
|
enum LC_STATE {
|
||||||
|
LCS_NONE,
|
||||||
|
LCS_FIRST,
|
||||||
|
LCS_SECOND,
|
||||||
|
LCS_THIRD
|
||||||
|
};
|
||||||
|
|
||||||
|
class CDMREmbeddedData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CDMREmbeddedData();
|
||||||
|
~CDMREmbeddedData();
|
||||||
|
|
||||||
|
bool addData(const unsigned char* data, unsigned char lcss);
|
||||||
|
|
||||||
|
CDMRLC* getLC() const;
|
||||||
|
void setLC(const CDMRLC& lc);
|
||||||
|
|
||||||
|
unsigned char getData(unsigned char* data, unsigned char n) const;
|
||||||
|
|
||||||
|
bool getRawData(unsigned char* data) const;
|
||||||
|
|
||||||
|
bool isValid() const;
|
||||||
|
FLCO getFLCO() const;
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool* m_raw;
|
||||||
|
LC_STATE m_state;
|
||||||
|
bool* m_data;
|
||||||
|
FLCO m_FLCO;
|
||||||
|
bool m_valid;
|
||||||
|
|
||||||
|
void decodeEmbeddedData();
|
||||||
|
void encodeEmbeddedData();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -17,24 +17,26 @@
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "FullLC.h"
|
#include "DMRFullLC.h"
|
||||||
#include "Log.h"
|
|
||||||
#include "DMRDefines.h"
|
#include "DMRDefines.h"
|
||||||
#include "RS129.h"
|
#include "RS129.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
CFullLC::CFullLC() :
|
CDMRFullLC::CDMRFullLC() :
|
||||||
m_bptc()
|
m_bptc()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CFullLC::~CFullLC()
|
CDMRFullLC::~CDMRFullLC()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CLC* CFullLC::decode(const unsigned char* data, unsigned char type)
|
CDMRLC* CDMRFullLC::decode(const unsigned char* data, unsigned char type)
|
||||||
{
|
{
|
||||||
assert(data != NULL);
|
assert(data != NULL);
|
||||||
|
|
||||||
|
@ -59,17 +61,13 @@ CLC* CFullLC::decode(const unsigned char* data, unsigned char type)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CRS129::check(lcData)) {
|
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 NULL;
|
||||||
|
|
||||||
|
return new CDMRLC(lcData);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new CLC(lcData);
|
void CDMRFullLC::encode(const CDMRLC& lc, unsigned char* data, unsigned char type)
|
||||||
}
|
|
||||||
|
|
||||||
void CFullLC::encode(const CLC& lc, unsigned char* data, unsigned char type)
|
|
||||||
{
|
{
|
||||||
assert(data != NULL);
|
assert(data != NULL);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,23 +16,23 @@
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FullLC_H
|
#ifndef DMRFullLC_H
|
||||||
#define FullLC_H
|
#define DMRFullLC_H
|
||||||
|
|
||||||
#include "LC.h"
|
#include "DMRLC.h"
|
||||||
#include "SlotType.h"
|
#include "DMRSlotType.h"
|
||||||
|
|
||||||
#include "BPTC19696.h"
|
#include "BPTC19696.h"
|
||||||
|
|
||||||
class CFullLC
|
class CDMRFullLC
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CFullLC();
|
CDMRFullLC();
|
||||||
~CFullLC();
|
~CDMRFullLC();
|
||||||
|
|
||||||
CLC* decode(const unsigned char* data, unsigned char type);
|
CDMRLC* decode(const unsigned char* data, unsigned char type);
|
||||||
|
|
||||||
void encode(const CLC& lc, unsigned char* data, unsigned char type);
|
void encode(const CDMRLC& lc, unsigned char* data, unsigned char type);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CBPTC19696 m_bptc;
|
CBPTC19696 m_bptc;
|
145242
DMRIds.dat
Normal file
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2019 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,59 +16,72 @@
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "LC.h"
|
#include "DMRLC.h"
|
||||||
|
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
CLC::CLC(FLCO flco, unsigned int srcId, unsigned int dstId) :
|
CDMRLC::CDMRLC(FLCO flco, unsigned int srcId, unsigned int dstId) :
|
||||||
m_PF(false),
|
m_PF(false),
|
||||||
|
m_R(false),
|
||||||
m_FLCO(flco),
|
m_FLCO(flco),
|
||||||
m_FID(0U),
|
m_FID(0U),
|
||||||
|
m_options(0U),
|
||||||
m_srcId(srcId),
|
m_srcId(srcId),
|
||||||
m_dstId(dstId)
|
m_dstId(dstId)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CLC::CLC(const unsigned char* bytes) :
|
CDMRLC::CDMRLC(const unsigned char* bytes) :
|
||||||
m_PF(false),
|
m_PF(false),
|
||||||
|
m_R(false),
|
||||||
m_FLCO(FLCO_GROUP),
|
m_FLCO(FLCO_GROUP),
|
||||||
m_FID(0U),
|
m_FID(0U),
|
||||||
|
m_options(0U),
|
||||||
m_srcId(0U),
|
m_srcId(0U),
|
||||||
m_dstId(0U)
|
m_dstId(0U)
|
||||||
{
|
{
|
||||||
assert(bytes != NULL);
|
assert(bytes != NULL);
|
||||||
|
|
||||||
m_PF = (bytes[0U] & 0x80U) == 0x80U;
|
m_PF = (bytes[0U] & 0x80U) == 0x80U;
|
||||||
|
m_R = (bytes[0U] & 0x40U) == 0x40U;
|
||||||
|
|
||||||
m_FLCO = FLCO(bytes[0U] & 0x3FU);
|
m_FLCO = FLCO(bytes[0U] & 0x3FU);
|
||||||
|
|
||||||
m_FID = bytes[1U];
|
m_FID = bytes[1U];
|
||||||
|
|
||||||
|
m_options = bytes[2U];
|
||||||
|
|
||||||
m_dstId = bytes[3U] << 16 | bytes[4U] << 8 | bytes[5U];
|
m_dstId = bytes[3U] << 16 | bytes[4U] << 8 | bytes[5U];
|
||||||
m_srcId = bytes[6U] << 16 | bytes[7U] << 8 | bytes[8U];
|
m_srcId = bytes[6U] << 16 | bytes[7U] << 8 | bytes[8U];
|
||||||
}
|
}
|
||||||
|
|
||||||
CLC::CLC(const bool* bits) :
|
CDMRLC::CDMRLC(const bool* bits) :
|
||||||
m_PF(false),
|
m_PF(false),
|
||||||
|
m_R(false),
|
||||||
m_FLCO(FLCO_GROUP),
|
m_FLCO(FLCO_GROUP),
|
||||||
m_FID(0U),
|
m_FID(0U),
|
||||||
|
m_options(0U),
|
||||||
m_srcId(0U),
|
m_srcId(0U),
|
||||||
m_dstId(0U)
|
m_dstId(0U)
|
||||||
{
|
{
|
||||||
assert(bits != NULL);
|
assert(bits != NULL);
|
||||||
|
|
||||||
m_PF = bits[0U];
|
m_PF = bits[0U];
|
||||||
|
m_R = bits[1U];
|
||||||
|
|
||||||
unsigned char temp1, temp2;
|
unsigned char temp1, temp2, temp3;
|
||||||
CUtils::bitsToByteBE(bits + 0U, temp1);
|
CUtils::bitsToByteBE(bits + 0U, temp1);
|
||||||
m_FLCO = FLCO(temp1 & 0x3FU);
|
m_FLCO = FLCO(temp1 & 0x3FU);
|
||||||
|
|
||||||
CUtils::bitsToByteBE(bits + 8U, temp2);
|
CUtils::bitsToByteBE(bits + 8U, temp2);
|
||||||
m_FID = temp2;
|
m_FID = temp2;
|
||||||
|
|
||||||
|
CUtils::bitsToByteBE(bits + 16U, temp3);
|
||||||
|
m_options = temp3;
|
||||||
|
|
||||||
unsigned char d1, d2, d3;
|
unsigned char d1, d2, d3;
|
||||||
CUtils::bitsToByteBE(bits + 24U, d1);
|
CUtils::bitsToByteBE(bits + 24U, d1);
|
||||||
CUtils::bitsToByteBE(bits + 32U, d2);
|
CUtils::bitsToByteBE(bits + 32U, d2);
|
||||||
|
@ -83,20 +96,22 @@ m_dstId(0U)
|
||||||
m_dstId = d1 << 16 | d2 << 8 | d3;
|
m_dstId = d1 << 16 | d2 << 8 | d3;
|
||||||
}
|
}
|
||||||
|
|
||||||
CLC::CLC() :
|
CDMRLC::CDMRLC() :
|
||||||
m_PF(false),
|
m_PF(false),
|
||||||
|
m_R(false),
|
||||||
m_FLCO(FLCO_GROUP),
|
m_FLCO(FLCO_GROUP),
|
||||||
m_FID(0U),
|
m_FID(0U),
|
||||||
|
m_options(0U),
|
||||||
m_srcId(0U),
|
m_srcId(0U),
|
||||||
m_dstId(0U)
|
m_dstId(0U)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
CLC::~CLC()
|
CDMRLC::~CDMRLC()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void CLC::getData(unsigned char* bytes) const
|
void CDMRLC::getData(unsigned char* bytes) const
|
||||||
{
|
{
|
||||||
assert(bytes != NULL);
|
assert(bytes != NULL);
|
||||||
|
|
||||||
|
@ -105,8 +120,13 @@ void CLC::getData(unsigned char* bytes) const
|
||||||
if (m_PF)
|
if (m_PF)
|
||||||
bytes[0U] |= 0x80U;
|
bytes[0U] |= 0x80U;
|
||||||
|
|
||||||
|
if (m_R)
|
||||||
|
bytes[0U] |= 0x40U;
|
||||||
|
|
||||||
bytes[1U] = m_FID;
|
bytes[1U] = m_FID;
|
||||||
|
|
||||||
|
bytes[2U] = m_options;
|
||||||
|
|
||||||
bytes[3U] = m_dstId >> 16;
|
bytes[3U] = m_dstId >> 16;
|
||||||
bytes[4U] = m_dstId >> 8;
|
bytes[4U] = m_dstId >> 8;
|
||||||
bytes[5U] = m_dstId >> 0;
|
bytes[5U] = m_dstId >> 0;
|
||||||
|
@ -116,8 +136,10 @@ void CLC::getData(unsigned char* bytes) const
|
||||||
bytes[8U] = m_srcId >> 0;
|
bytes[8U] = m_srcId >> 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CLC::getData(bool* bits) const
|
void CDMRLC::getData(bool* bits) const
|
||||||
{
|
{
|
||||||
|
assert(bits != NULL);
|
||||||
|
|
||||||
unsigned char bytes[9U];
|
unsigned char bytes[9U];
|
||||||
getData(bytes);
|
getData(bytes);
|
||||||
|
|
||||||
|
@ -132,52 +154,63 @@ void CLC::getData(bool* bits) const
|
||||||
CUtils::byteToBitsBE(bytes[8U], bits + 64U);
|
CUtils::byteToBitsBE(bytes[8U], bits + 64U);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CLC::getPF() const
|
bool CDMRLC::getPF() const
|
||||||
{
|
{
|
||||||
return m_PF;
|
return m_PF;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CLC::setPF(bool pf)
|
void CDMRLC::setPF(bool pf)
|
||||||
{
|
{
|
||||||
m_PF = pf;
|
m_PF = pf;
|
||||||
}
|
}
|
||||||
|
|
||||||
FLCO CLC::getFLCO() const
|
FLCO CDMRLC::getFLCO() const
|
||||||
{
|
{
|
||||||
return m_FLCO;
|
return m_FLCO;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CLC::setFLCO(FLCO flco)
|
void CDMRLC::setFLCO(FLCO flco)
|
||||||
{
|
{
|
||||||
m_FLCO = flco;
|
m_FLCO = flco;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char CLC::getFID() const
|
unsigned char CDMRLC::getFID() const
|
||||||
{
|
{
|
||||||
return m_FID;
|
return m_FID;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CLC::setFID(unsigned char fid)
|
void CDMRLC::setFID(unsigned char fid)
|
||||||
{
|
{
|
||||||
m_FID = fid;
|
m_FID = fid;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int CLC::getSrcId() const
|
bool CDMRLC::getOVCM() const
|
||||||
|
{
|
||||||
|
return (m_options & 0x04U) == 0x04U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMRLC::setOVCM(bool ovcm)
|
||||||
|
{
|
||||||
|
if (ovcm)
|
||||||
|
m_options |= 0x04U;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CDMRLC::getSrcId() const
|
||||||
{
|
{
|
||||||
return m_srcId;
|
return m_srcId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CLC::setSrcId(unsigned int id)
|
void CDMRLC::setSrcId(unsigned int id)
|
||||||
{
|
{
|
||||||
m_srcId = id;
|
m_srcId = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int CLC::getDstId() const
|
unsigned int CDMRLC::getDstId() const
|
||||||
{
|
{
|
||||||
return m_dstId;
|
return m_dstId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CLC::setDstId(unsigned int id)
|
void CDMRLC::setDstId(unsigned int id)
|
||||||
{
|
{
|
||||||
m_dstId = id;
|
m_dstId = id;
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2019 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,19 +16,19 @@
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if !defined(LC_H)
|
#if !defined(DMRLC_H)
|
||||||
#define LC_H
|
#define DMRLC_H
|
||||||
|
|
||||||
#include "DMRDefines.h"
|
#include "DMRDefines.h"
|
||||||
|
|
||||||
class CLC
|
class CDMRLC
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CLC(FLCO flco, unsigned int srcId, unsigned int dstId);
|
CDMRLC(FLCO flco, unsigned int srcId, unsigned int dstId);
|
||||||
CLC(const unsigned char* bytes);
|
CDMRLC(const unsigned char* bytes);
|
||||||
CLC(const bool* bits);
|
CDMRLC(const bool* bits);
|
||||||
CLC();
|
CDMRLC();
|
||||||
~CLC();
|
~CDMRLC();
|
||||||
|
|
||||||
void getData(unsigned char* bytes) const;
|
void getData(unsigned char* bytes) const;
|
||||||
void getData(bool* bits) const;
|
void getData(bool* bits) const;
|
||||||
|
@ -39,6 +39,9 @@ public:
|
||||||
FLCO getFLCO() const;
|
FLCO getFLCO() const;
|
||||||
void setFLCO(FLCO flco);
|
void setFLCO(FLCO flco);
|
||||||
|
|
||||||
|
bool getOVCM() const;
|
||||||
|
void setOVCM(bool ovcm);
|
||||||
|
|
||||||
unsigned char getFID() const;
|
unsigned char getFID() const;
|
||||||
void setFID(unsigned char fid);
|
void setFID(unsigned char fid);
|
||||||
|
|
||||||
|
@ -50,8 +53,10 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_PF;
|
bool m_PF;
|
||||||
|
bool m_R;
|
||||||
FLCO m_FLCO;
|
FLCO m_FLCO;
|
||||||
unsigned char m_FID;
|
unsigned char m_FID;
|
||||||
|
unsigned char m_options;
|
||||||
unsigned int m_srcId;
|
unsigned int m_srcId;
|
||||||
unsigned int m_dstId;
|
unsigned int m_dstId;
|
||||||
};
|
};
|
126
DMRLookup.cpp
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016,2017 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "DMRLookup.h"
|
||||||
|
#include "Timer.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cctype>
|
||||||
|
|
||||||
|
CDMRLookup::CDMRLookup(const std::string& filename, unsigned int reloadTime) :
|
||||||
|
CThread(),
|
||||||
|
m_filename(filename),
|
||||||
|
m_reloadTime(reloadTime),
|
||||||
|
m_table(),
|
||||||
|
m_stop(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CDMRLookup::~CDMRLookup()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMRLookup::read()
|
||||||
|
{
|
||||||
|
bool ret = m_table.load(m_filename);
|
||||||
|
|
||||||
|
if (m_reloadTime > 0U)
|
||||||
|
run();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMRLookup::entry()
|
||||||
|
{
|
||||||
|
LogInfo("Started the DMR Id lookup reload thread");
|
||||||
|
|
||||||
|
CTimer timer(1U, 3600U * m_reloadTime);
|
||||||
|
timer.start();
|
||||||
|
|
||||||
|
while (!m_stop) {
|
||||||
|
sleep(1000U);
|
||||||
|
|
||||||
|
timer.clock();
|
||||||
|
if (timer.hasExpired()) {
|
||||||
|
m_table.load(m_filename);
|
||||||
|
timer.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LogInfo("Stopped the DMR Id lookup reload thread");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMRLookup::stop()
|
||||||
|
{
|
||||||
|
if (m_reloadTime == 0U) {
|
||||||
|
delete this;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_stop = true;
|
||||||
|
|
||||||
|
wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMRLookup::findWithName(unsigned int id, class CUserDBentry *entry)
|
||||||
|
{
|
||||||
|
if (id == 0xFFFFFFU) {
|
||||||
|
entry->clear();
|
||||||
|
entry->set(keyCALLSIGN, "ALL");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_table.lookup(id, entry)) {
|
||||||
|
LogDebug("FindWithName =%s %s", entry->get(keyCALLSIGN).c_str(), entry->get(keyFIRST_NAME).c_str());
|
||||||
|
} else {
|
||||||
|
entry->clear();
|
||||||
|
|
||||||
|
char text[10U];
|
||||||
|
::snprintf(text, sizeof(text), "%u", id);
|
||||||
|
entry->set(keyCALLSIGN, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CDMRLookup::find(unsigned int id)
|
||||||
|
{
|
||||||
|
std::string callsign;
|
||||||
|
|
||||||
|
if (id == 0xFFFFFFU)
|
||||||
|
return std::string("ALL");
|
||||||
|
|
||||||
|
class CUserDBentry entry;
|
||||||
|
if (m_table.lookup(id, &entry)) {
|
||||||
|
callsign = entry.get(keyCALLSIGN);
|
||||||
|
} else {
|
||||||
|
char text[10U];
|
||||||
|
::snprintf(text, sizeof(text), "%u", id);
|
||||||
|
callsign = std::string(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
return callsign;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMRLookup::exists(unsigned int id)
|
||||||
|
{
|
||||||
|
return m_table.lookup(id, NULL);
|
||||||
|
}
|
50
DMRLookup.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016,2017 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DMRLookup_H
|
||||||
|
#define DMRLookup_H
|
||||||
|
|
||||||
|
#include "Thread.h"
|
||||||
|
#include "UserDB.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class CDMRLookup : public CThread {
|
||||||
|
public:
|
||||||
|
CDMRLookup(const std::string& filename, unsigned int reloadTime);
|
||||||
|
virtual ~CDMRLookup();
|
||||||
|
|
||||||
|
bool read();
|
||||||
|
|
||||||
|
virtual void entry();
|
||||||
|
|
||||||
|
std::string find(unsigned int id);
|
||||||
|
void findWithName(unsigned int id, class CUserDBentry *entry);
|
||||||
|
|
||||||
|
bool exists(unsigned int id);
|
||||||
|
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_filename;
|
||||||
|
unsigned int m_reloadTime;
|
||||||
|
class CUserDB m_table;
|
||||||
|
bool m_stop;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
675
DMRNetwork.cpp
Normal file
|
@ -0,0 +1,675 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2019 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "DMRNetwork.h"
|
||||||
|
|
||||||
|
#include "StopWatch.h"
|
||||||
|
#include "SHA256.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
const unsigned int BUFFER_LENGTH = 500U;
|
||||||
|
|
||||||
|
const unsigned int HOMEBREW_DATA_PACKET_LENGTH = 55U;
|
||||||
|
|
||||||
|
|
||||||
|
CDMRNetwork::CDMRNetwork(const std::string& address, unsigned int port, unsigned int local, unsigned int id, const std::string& password, bool duplex, const char* version, bool debug, bool slot1, bool slot2, HW_TYPE hwType) :
|
||||||
|
m_addressStr(address),
|
||||||
|
m_address(),
|
||||||
|
m_port(port),
|
||||||
|
m_id(NULL),
|
||||||
|
m_password(password),
|
||||||
|
m_duplex(duplex),
|
||||||
|
m_version(version),
|
||||||
|
m_debug(debug),
|
||||||
|
m_socket(local),
|
||||||
|
m_enabled(false),
|
||||||
|
m_slot1(slot1),
|
||||||
|
m_slot2(slot2),
|
||||||
|
m_hwType(hwType),
|
||||||
|
m_status(WAITING_CONNECT),
|
||||||
|
m_retryTimer(1000U, 10U),
|
||||||
|
m_timeoutTimer(1000U, 60U),
|
||||||
|
m_buffer(NULL),
|
||||||
|
m_salt(NULL),
|
||||||
|
m_streamId(NULL),
|
||||||
|
m_rxData(1000U, "DMR Network"),
|
||||||
|
m_options(),
|
||||||
|
m_callsign(),
|
||||||
|
m_rxFrequency(0U),
|
||||||
|
m_txFrequency(0U),
|
||||||
|
m_power(0U),
|
||||||
|
m_colorCode(0U),
|
||||||
|
m_latitude(0.0F),
|
||||||
|
m_longitude(0.0F),
|
||||||
|
m_height(0),
|
||||||
|
m_location(),
|
||||||
|
m_description(),
|
||||||
|
m_url(),
|
||||||
|
m_beacon(false)
|
||||||
|
{
|
||||||
|
assert(!address.empty());
|
||||||
|
assert(port > 0U);
|
||||||
|
assert(id > 1000U);
|
||||||
|
assert(!password.empty());
|
||||||
|
|
||||||
|
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_id[0U] = id >> 24;
|
||||||
|
m_id[1U] = id >> 16;
|
||||||
|
m_id[2U] = id >> 8;
|
||||||
|
m_id[3U] = id >> 0;
|
||||||
|
|
||||||
|
CStopWatch stopWatch;
|
||||||
|
::srand(stopWatch.start());
|
||||||
|
|
||||||
|
m_streamId[0U] = ::rand() + 1U;
|
||||||
|
m_streamId[1U] = ::rand() + 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
CDMRNetwork::~CDMRNetwork()
|
||||||
|
{
|
||||||
|
delete[] m_buffer;
|
||||||
|
delete[] m_salt;
|
||||||
|
delete[] m_streamId;
|
||||||
|
delete[] m_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMRNetwork::setOptions(const std::string& options)
|
||||||
|
{
|
||||||
|
m_options = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMRNetwork::setConfig(const std::string& callsign, unsigned int rxFrequency, unsigned int txFrequency, unsigned int power, unsigned int colorCode, float latitude, float longitude, int height, const std::string& location, const std::string& description, const std::string& url)
|
||||||
|
{
|
||||||
|
m_callsign = callsign;
|
||||||
|
m_rxFrequency = rxFrequency;
|
||||||
|
m_txFrequency = txFrequency;
|
||||||
|
m_power = power;
|
||||||
|
m_colorCode = colorCode;
|
||||||
|
m_latitude = latitude;
|
||||||
|
m_longitude = longitude;
|
||||||
|
m_height = height;
|
||||||
|
m_location = location;
|
||||||
|
m_description = description;
|
||||||
|
m_url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMRNetwork::open()
|
||||||
|
{
|
||||||
|
LogMessage("DMR, Opening DMR Network");
|
||||||
|
|
||||||
|
if (m_address.s_addr == INADDR_NONE)
|
||||||
|
m_address = CUDPSocket::lookup(m_addressStr);
|
||||||
|
|
||||||
|
m_status = WAITING_CONNECT;
|
||||||
|
m_timeoutTimer.stop();
|
||||||
|
m_retryTimer.start();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMRNetwork::enable(bool enabled)
|
||||||
|
{
|
||||||
|
if (!enabled && m_enabled)
|
||||||
|
m_rxData.clear();
|
||||||
|
|
||||||
|
m_enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMRNetwork::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;
|
||||||
|
|
||||||
|
// DMO mode slot disabling
|
||||||
|
if (slotNo == 1U && !m_duplex)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Individual slot disabling
|
||||||
|
if (slotNo == 1U && !m_slot1)
|
||||||
|
return false;
|
||||||
|
if (slotNo == 2U && !m_slot2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
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 CDMRNetwork::write(const CDMRData& data)
|
||||||
|
{
|
||||||
|
if (m_status != RUNNING)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
unsigned char buffer[HOMEBREW_DATA_PACKET_LENGTH];
|
||||||
|
::memset(buffer, 0x00U, HOMEBREW_DATA_PACKET_LENGTH);
|
||||||
|
|
||||||
|
buffer[0U] = 'D';
|
||||||
|
buffer[1U] = 'M';
|
||||||
|
buffer[2U] = 'R';
|
||||||
|
buffer[3U] = 'D';
|
||||||
|
|
||||||
|
unsigned int srcId = data.getSrcId();
|
||||||
|
buffer[5U] = srcId >> 16;
|
||||||
|
buffer[6U] = srcId >> 8;
|
||||||
|
buffer[7U] = srcId >> 0;
|
||||||
|
|
||||||
|
unsigned int dstId = data.getDstId();
|
||||||
|
buffer[8U] = dstId >> 16;
|
||||||
|
buffer[9U] = dstId >> 8;
|
||||||
|
buffer[10U] = dstId >> 0;
|
||||||
|
|
||||||
|
::memcpy(buffer + 11U, m_id, 4U);
|
||||||
|
|
||||||
|
unsigned int slotNo = data.getSlotNo();
|
||||||
|
|
||||||
|
// Individual slot disabling
|
||||||
|
if (slotNo == 1U && !m_slot1)
|
||||||
|
return false;
|
||||||
|
if (slotNo == 2U && !m_slot2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
buffer[15U] = slotNo == 1U ? 0x00U : 0x80U;
|
||||||
|
|
||||||
|
FLCO flco = data.getFLCO();
|
||||||
|
buffer[15U] |= flco == FLCO_GROUP ? 0x00U : 0x40U;
|
||||||
|
|
||||||
|
unsigned int slotIndex = slotNo - 1U;
|
||||||
|
|
||||||
|
unsigned 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)
|
||||||
|
m_streamId[slotIndex] = ::rand() + 1U;
|
||||||
|
|
||||||
|
if (dataType == DT_CSBK || dataType == DT_DATA_HEADER)
|
||||||
|
m_streamId[slotIndex] = ::rand() + 1U;
|
||||||
|
|
||||||
|
buffer[15U] |= (0x20U | dataType);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[4U] = data.getSeqNo();
|
||||||
|
|
||||||
|
::memcpy(buffer + 16U, m_streamId + slotIndex, 4U);
|
||||||
|
|
||||||
|
data.getData(buffer + 20U);
|
||||||
|
|
||||||
|
buffer[53U] = data.getBER();
|
||||||
|
|
||||||
|
buffer[54U] = data.getRSSI();
|
||||||
|
|
||||||
|
if (m_debug)
|
||||||
|
CUtils::dump(1U, "Network Transmitted", buffer, HOMEBREW_DATA_PACKET_LENGTH);
|
||||||
|
|
||||||
|
write(buffer, HOMEBREW_DATA_PACKET_LENGTH);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMRNetwork::writeRadioPosition(unsigned int id, const unsigned char* data)
|
||||||
|
{
|
||||||
|
if (m_status != RUNNING)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
unsigned char buffer[20U];
|
||||||
|
|
||||||
|
::memcpy(buffer + 0U, "DMRG", 4U);
|
||||||
|
|
||||||
|
::memcpy(buffer + 4U, m_id, 4U);
|
||||||
|
|
||||||
|
buffer[8U] = id >> 16;
|
||||||
|
buffer[9U] = id >> 8;
|
||||||
|
buffer[10U] = id >> 0;
|
||||||
|
|
||||||
|
::memcpy(buffer + 11U, data + 2U, 7U);
|
||||||
|
|
||||||
|
return write(buffer, 18U);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMRNetwork::writeTalkerAlias(unsigned int id, unsigned char type, const unsigned char* data)
|
||||||
|
{
|
||||||
|
if (m_status != RUNNING)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
unsigned char buffer[20U];
|
||||||
|
|
||||||
|
::memcpy(buffer + 0U, "DMRA", 4U);
|
||||||
|
|
||||||
|
::memcpy(buffer + 4U, m_id, 4U);
|
||||||
|
|
||||||
|
buffer[8U] = id >> 16;
|
||||||
|
buffer[9U] = id >> 8;
|
||||||
|
buffer[10U] = id >> 0;
|
||||||
|
|
||||||
|
buffer[11U] = type;
|
||||||
|
|
||||||
|
::memcpy(buffer + 12U, data + 2U, 7U);
|
||||||
|
|
||||||
|
return write(buffer, 19U);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMRNetwork::writeHomePosition(float latitude, float longitude)
|
||||||
|
{
|
||||||
|
m_latitude = latitude;
|
||||||
|
m_longitude = longitude;
|
||||||
|
|
||||||
|
if (m_status != RUNNING)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
char buffer[50U];
|
||||||
|
|
||||||
|
::memcpy(buffer + 0U, "RPTG", 4U);
|
||||||
|
::memcpy(buffer + 4U, m_id, 4U);
|
||||||
|
|
||||||
|
::sprintf(buffer + 8U, "%08f%09f", latitude, longitude);
|
||||||
|
|
||||||
|
return write((unsigned char*)buffer, 25U);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMRNetwork::close()
|
||||||
|
{
|
||||||
|
LogMessage("DMR, Closing DMR Network");
|
||||||
|
|
||||||
|
if (m_status == RUNNING) {
|
||||||
|
unsigned char buffer[9U];
|
||||||
|
::memcpy(buffer + 0U, "RPTCL", 5U);
|
||||||
|
::memcpy(buffer + 5U, m_id, 4U);
|
||||||
|
write(buffer, 9U);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_socket.close();
|
||||||
|
|
||||||
|
m_retryTimer.stop();
|
||||||
|
m_timeoutTimer.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMRNetwork::clock(unsigned int ms)
|
||||||
|
{
|
||||||
|
if (m_status == WAITING_CONNECT) {
|
||||||
|
m_retryTimer.clock(ms);
|
||||||
|
if (m_retryTimer.isRunning() && m_retryTimer.hasExpired()) {
|
||||||
|
bool ret = m_socket.open();
|
||||||
|
if (ret) {
|
||||||
|
ret = writeLogin();
|
||||||
|
if (!ret)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_status = WAITING_LOGIN;
|
||||||
|
m_timeoutTimer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_retryTimer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
in_addr address;
|
||||||
|
unsigned int port;
|
||||||
|
int length = m_socket.read(m_buffer, BUFFER_LENGTH, address, port);
|
||||||
|
if (length < 0) {
|
||||||
|
LogError("DMR, Socket has failed, retrying connection to the master");
|
||||||
|
close();
|
||||||
|
open();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (m_debug && length > 0)
|
||||||
|
// CUtils::dump(1U, "Network Received", m_buffer, length);
|
||||||
|
|
||||||
|
if (length > 0 && m_address.s_addr == address.s_addr && m_port == port) {
|
||||||
|
if (::memcmp(m_buffer, "DMRD", 4U) == 0) {
|
||||||
|
if (m_enabled) {
|
||||||
|
if (m_debug)
|
||||||
|
CUtils::dump(1U, "Network Received", m_buffer, length);
|
||||||
|
|
||||||
|
unsigned char len = length;
|
||||||
|
m_rxData.addData(&len, 1U);
|
||||||
|
m_rxData.addData(m_buffer, len);
|
||||||
|
}
|
||||||
|
} else if (::memcmp(m_buffer, "MSTNAK", 6U) == 0) {
|
||||||
|
if (m_status == RUNNING) {
|
||||||
|
LogWarning("DMR, Login to the master has failed, retrying login ...");
|
||||||
|
m_status = WAITING_LOGIN;
|
||||||
|
m_timeoutTimer.start();
|
||||||
|
m_retryTimer.start();
|
||||||
|
} else {
|
||||||
|
/* Once the modem death spiral has been prevented in Modem.cpp
|
||||||
|
the Network sometimes times out and reaches here.
|
||||||
|
We want it to reconnect so... */
|
||||||
|
LogError("DMR, Login to the master has failed, retrying network ...");
|
||||||
|
close();
|
||||||
|
open();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (::memcmp(m_buffer, "RPTACK", 6U) == 0) {
|
||||||
|
switch (m_status) {
|
||||||
|
case WAITING_LOGIN:
|
||||||
|
LogDebug("DMR, Sending authorisation");
|
||||||
|
::memcpy(m_salt, m_buffer + 6U, sizeof(uint32_t));
|
||||||
|
writeAuthorisation();
|
||||||
|
m_status = WAITING_AUTHORISATION;
|
||||||
|
m_timeoutTimer.start();
|
||||||
|
m_retryTimer.start();
|
||||||
|
break;
|
||||||
|
case WAITING_AUTHORISATION:
|
||||||
|
LogDebug("DMR, Sending configuration");
|
||||||
|
writeConfig();
|
||||||
|
m_status = WAITING_CONFIG;
|
||||||
|
m_timeoutTimer.start();
|
||||||
|
m_retryTimer.start();
|
||||||
|
break;
|
||||||
|
case WAITING_CONFIG:
|
||||||
|
if (m_options.empty()) {
|
||||||
|
LogMessage("DMR, Logged into the master successfully");
|
||||||
|
m_status = RUNNING;
|
||||||
|
} else {
|
||||||
|
LogDebug("DMR, Sending options");
|
||||||
|
writeOptions();
|
||||||
|
m_status = WAITING_OPTIONS;
|
||||||
|
}
|
||||||
|
m_timeoutTimer.start();
|
||||||
|
m_retryTimer.start();
|
||||||
|
break;
|
||||||
|
case WAITING_OPTIONS:
|
||||||
|
LogMessage("DMR, Logged into the master successfully");
|
||||||
|
m_status = RUNNING;
|
||||||
|
m_timeoutTimer.start();
|
||||||
|
m_retryTimer.start();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (::memcmp(m_buffer, "MSTCL", 5U) == 0) {
|
||||||
|
LogError("DMR, Master is closing down");
|
||||||
|
close();
|
||||||
|
open();
|
||||||
|
} else if (::memcmp(m_buffer, "MSTPONG", 7U) == 0) {
|
||||||
|
m_timeoutTimer.start();
|
||||||
|
} else if (::memcmp(m_buffer, "RPTSBKN", 7U) == 0) {
|
||||||
|
m_beacon = true;
|
||||||
|
} else {
|
||||||
|
CUtils::dump("Unknown packet from the master", m_buffer, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_retryTimer.clock(ms);
|
||||||
|
if (m_retryTimer.isRunning() && m_retryTimer.hasExpired()) {
|
||||||
|
switch (m_status) {
|
||||||
|
case WAITING_LOGIN:
|
||||||
|
writeLogin();
|
||||||
|
break;
|
||||||
|
case WAITING_AUTHORISATION:
|
||||||
|
writeAuthorisation();
|
||||||
|
break;
|
||||||
|
case WAITING_OPTIONS:
|
||||||
|
writeOptions();
|
||||||
|
break;
|
||||||
|
case WAITING_CONFIG:
|
||||||
|
writeConfig();
|
||||||
|
break;
|
||||||
|
case RUNNING:
|
||||||
|
writePing();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_retryTimer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_timeoutTimer.clock(ms);
|
||||||
|
if (m_timeoutTimer.isRunning() && m_timeoutTimer.hasExpired()) {
|
||||||
|
LogError("DMR, Connection to the master has timed out, retrying connection");
|
||||||
|
close();
|
||||||
|
open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMRNetwork::writeLogin()
|
||||||
|
{
|
||||||
|
unsigned char buffer[8U];
|
||||||
|
|
||||||
|
::memcpy(buffer + 0U, "RPTL", 4U);
|
||||||
|
::memcpy(buffer + 4U, m_id, 4U);
|
||||||
|
|
||||||
|
return write(buffer, 8U);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMRNetwork::writeAuthorisation()
|
||||||
|
{
|
||||||
|
size_t size = m_password.size();
|
||||||
|
|
||||||
|
unsigned char* in = new unsigned char[size + sizeof(uint32_t)];
|
||||||
|
::memcpy(in, m_salt, sizeof(uint32_t));
|
||||||
|
for (size_t i = 0U; i < size; i++)
|
||||||
|
in[i + sizeof(uint32_t)] = m_password.at(i);
|
||||||
|
|
||||||
|
unsigned char out[40U];
|
||||||
|
::memcpy(out + 0U, "RPTK", 4U);
|
||||||
|
::memcpy(out + 4U, m_id, 4U);
|
||||||
|
|
||||||
|
CSHA256 sha256;
|
||||||
|
sha256.buffer(in, (unsigned int)(size + sizeof(uint32_t)), out + 8U);
|
||||||
|
|
||||||
|
delete[] in;
|
||||||
|
|
||||||
|
return write(out, 40U);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMRNetwork::writeOptions()
|
||||||
|
{
|
||||||
|
char buffer[300U];
|
||||||
|
|
||||||
|
::memcpy(buffer + 0U, "RPTO", 4U);
|
||||||
|
::memcpy(buffer + 4U, m_id, 4U);
|
||||||
|
::strcpy(buffer + 8U, m_options.c_str());
|
||||||
|
|
||||||
|
return write((unsigned char*)buffer, (unsigned int)m_options.length() + 8U);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMRNetwork::writeConfig()
|
||||||
|
{
|
||||||
|
const char* software;
|
||||||
|
char slots = '0';
|
||||||
|
if (m_duplex) {
|
||||||
|
if (m_slot1 && m_slot2)
|
||||||
|
slots = '3';
|
||||||
|
else if (m_slot1 && !m_slot2)
|
||||||
|
slots = '1';
|
||||||
|
else if (!m_slot1 && m_slot2)
|
||||||
|
slots = '2';
|
||||||
|
|
||||||
|
switch (m_hwType) {
|
||||||
|
case HWT_MMDVM:
|
||||||
|
software = "MMDVM";
|
||||||
|
break;
|
||||||
|
case HWT_MMDVM_HS:
|
||||||
|
software = "MMDVM_MMDVM_HS";
|
||||||
|
break;
|
||||||
|
case HWT_MMDVM_HS_DUAL_HAT:
|
||||||
|
software = "MMDVM_MMDVM_HS_Dual_Hat";
|
||||||
|
break;
|
||||||
|
case HWT_NANO_HOTSPOT:
|
||||||
|
software = "MMDVM_Nano_hotSPOT";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
software = "MMDVM_Unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
slots = '4';
|
||||||
|
|
||||||
|
switch (m_hwType) {
|
||||||
|
case HWT_MMDVM:
|
||||||
|
software = "MMDVM_DMO";
|
||||||
|
break;
|
||||||
|
case HWT_DVMEGA:
|
||||||
|
software = "MMDVM_DVMega";
|
||||||
|
break;
|
||||||
|
case HWT_MMDVM_ZUMSPOT:
|
||||||
|
software = "MMDVM_ZUMspot";
|
||||||
|
break;
|
||||||
|
case HWT_MMDVM_HS_HAT:
|
||||||
|
software = "MMDVM_MMDVM_HS_Hat";
|
||||||
|
break;
|
||||||
|
case HWT_MMDVM_HS_DUAL_HAT:
|
||||||
|
software = "MMDVM_MMDVM_HS_Dual_Hat";
|
||||||
|
break;
|
||||||
|
case HWT_NANO_HOTSPOT:
|
||||||
|
software = "MMDVM_Nano_hotSPOT";
|
||||||
|
break;
|
||||||
|
case HWT_NANO_DV:
|
||||||
|
software = "MMDVM_Nano_DV";
|
||||||
|
break;
|
||||||
|
case HWT_D2RG_MMDVM_HS:
|
||||||
|
software = "MMDVM_D2RG_MMDVM_HS";
|
||||||
|
break;
|
||||||
|
case HWT_MMDVM_HS:
|
||||||
|
software = "MMDVM_MMDVM_HS";
|
||||||
|
break;
|
||||||
|
case HWT_OPENGD77_HS:
|
||||||
|
software = "MMDVM_OpenGD77_HS";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
software = "MMDVM_Unknown";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char buffer[400U];
|
||||||
|
|
||||||
|
::memcpy(buffer + 0U, "RPTC", 4U);
|
||||||
|
::memcpy(buffer + 4U, m_id, 4U);
|
||||||
|
|
||||||
|
char latitude[20U];
|
||||||
|
::sprintf(latitude, "%08f", m_latitude);
|
||||||
|
|
||||||
|
char longitude[20U];
|
||||||
|
::sprintf(longitude, "%09f", m_longitude);
|
||||||
|
|
||||||
|
unsigned int power = m_power;
|
||||||
|
if (power > 99U)
|
||||||
|
power = 99U;
|
||||||
|
|
||||||
|
int height = m_height;
|
||||||
|
if (height > 999)
|
||||||
|
height = 999;
|
||||||
|
|
||||||
|
::sprintf(buffer + 8U, "%-8.8s%09u%09u%02u%02u%8.8s%9.9s%03d%-20.20s%-19.19s%c%-124.124s%-40.40s%-40.40s", m_callsign.c_str(),
|
||||||
|
m_rxFrequency, m_txFrequency, power, m_colorCode, latitude, longitude, height, m_location.c_str(),
|
||||||
|
m_description.c_str(), slots, m_url.c_str(), m_version, software);
|
||||||
|
|
||||||
|
return write((unsigned char*)buffer, 302U);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMRNetwork::writePing()
|
||||||
|
{
|
||||||
|
unsigned char buffer[11U];
|
||||||
|
|
||||||
|
::memcpy(buffer + 0U, "RPTPING", 7U);
|
||||||
|
::memcpy(buffer + 7U, m_id, 4U);
|
||||||
|
|
||||||
|
return write(buffer, 11U);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMRNetwork::wantsBeacon()
|
||||||
|
{
|
||||||
|
bool beacon = m_beacon;
|
||||||
|
|
||||||
|
m_beacon = false;
|
||||||
|
|
||||||
|
return beacon;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMRNetwork::write(const unsigned char* data, unsigned int length)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
assert(length > 0U);
|
||||||
|
|
||||||
|
// if (m_debug)
|
||||||
|
// CUtils::dump(1U, "Network Transmitted", data, length);
|
||||||
|
|
||||||
|
bool ret = m_socket.write(data, length, m_address, m_port);
|
||||||
|
if (!ret) {
|
||||||
|
LogError("DMR, Socket has failed when writing data to the master, retrying connection");
|
||||||
|
m_socket.close();
|
||||||
|
open();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,31 +16,42 @@
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if !defined(HOMEBREWDMRIPSC_H)
|
#if !defined(DMRNetwork_H)
|
||||||
#define HOMEBREWDMRIPSC_H
|
#define DMRNetwork_H
|
||||||
|
|
||||||
#include "UDPSocket.h"
|
#include "UDPSocket.h"
|
||||||
#include "Timer.h"
|
#include "Timer.h"
|
||||||
#include "RingBuffer.h"
|
#include "RingBuffer.h"
|
||||||
#include "DMRData.h"
|
#include "DMRData.h"
|
||||||
|
#include "Defines.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
class CHomebrewDMRIPSC
|
class CDMRNetwork
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CHomebrewDMRIPSC(const std::string& address, unsigned int port, unsigned int id, const std::string& password, const char* software, const char* version, bool debug);
|
CDMRNetwork(const std::string& address, unsigned int port, unsigned int local, unsigned int id, const std::string& password, bool duplex, const char* version, bool debug, bool slot1, bool slot2, HW_TYPE hwType);
|
||||||
~CHomebrewDMRIPSC();
|
~CDMRNetwork();
|
||||||
|
|
||||||
|
void setOptions(const std::string& options);
|
||||||
|
|
||||||
void setConfig(const std::string& callsign, unsigned int rxFrequency, unsigned int txFrequency, unsigned int power, unsigned int colorCode, float latitude, float longitude, int height, const std::string& location, const std::string& description, const std::string& url);
|
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 open();
|
||||||
|
|
||||||
|
void enable(bool enabled);
|
||||||
|
|
||||||
bool read(CDMRData& data);
|
bool read(CDMRData& data);
|
||||||
|
|
||||||
bool write(const CDMRData& data);
|
bool write(const CDMRData& data);
|
||||||
|
|
||||||
|
bool writeRadioPosition(unsigned int id, const unsigned char* data);
|
||||||
|
|
||||||
|
bool writeTalkerAlias(unsigned int id, unsigned char type, const unsigned char* data);
|
||||||
|
|
||||||
|
bool writeHomePosition(float latitude, float longitude);
|
||||||
|
|
||||||
bool wantsBeacon();
|
bool wantsBeacon();
|
||||||
|
|
||||||
void clock(unsigned int ms);
|
void clock(unsigned int ms);
|
||||||
|
@ -48,33 +59,40 @@ public:
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::string m_addressStr;
|
||||||
in_addr m_address;
|
in_addr m_address;
|
||||||
unsigned int m_port;
|
unsigned int m_port;
|
||||||
uint8_t* m_id;
|
uint8_t* m_id;
|
||||||
std::string m_password;
|
std::string m_password;
|
||||||
bool m_debug;
|
bool m_duplex;
|
||||||
const char* m_software;
|
|
||||||
const char* m_version;
|
const char* m_version;
|
||||||
|
bool m_debug;
|
||||||
CUDPSocket m_socket;
|
CUDPSocket m_socket;
|
||||||
|
bool m_enabled;
|
||||||
|
bool m_slot1;
|
||||||
|
bool m_slot2;
|
||||||
|
HW_TYPE m_hwType;
|
||||||
|
|
||||||
enum STATUS {
|
enum STATUS {
|
||||||
DISCONNECTED,
|
WAITING_CONNECT,
|
||||||
WAITING_LOGIN,
|
WAITING_LOGIN,
|
||||||
WAITING_AUTHORISATION,
|
WAITING_AUTHORISATION,
|
||||||
WAITING_CONFIG,
|
WAITING_CONFIG,
|
||||||
|
WAITING_OPTIONS,
|
||||||
RUNNING
|
RUNNING
|
||||||
};
|
};
|
||||||
|
|
||||||
STATUS m_status;
|
STATUS m_status;
|
||||||
CTimer m_retryTimer;
|
CTimer m_retryTimer;
|
||||||
CTimer m_timeoutTimer;
|
CTimer m_timeoutTimer;
|
||||||
CTimer m_pingTimer;
|
|
||||||
unsigned char* m_buffer;
|
unsigned char* m_buffer;
|
||||||
unsigned char* m_salt;
|
unsigned char* m_salt;
|
||||||
uint32_t* m_streamId;
|
uint32_t* m_streamId;
|
||||||
|
|
||||||
CRingBuffer<unsigned char> m_rxData;
|
CRingBuffer<unsigned char> m_rxData;
|
||||||
|
|
||||||
|
std::string m_options;
|
||||||
|
|
||||||
std::string m_callsign;
|
std::string m_callsign;
|
||||||
unsigned int m_rxFrequency;
|
unsigned int m_rxFrequency;
|
||||||
unsigned int m_txFrequency;
|
unsigned int m_txFrequency;
|
||||||
|
@ -91,6 +109,7 @@ private:
|
||||||
|
|
||||||
bool writeLogin();
|
bool writeLogin();
|
||||||
bool writeAuthorisation();
|
bool writeAuthorisation();
|
||||||
|
bool writeOptions();
|
||||||
bool writeConfig();
|
bool writeConfig();
|
||||||
bool writePing();
|
bool writePing();
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ShortLC.h"
|
#include "DMRShortLC.h"
|
||||||
|
|
||||||
#include "Hamming.h"
|
#include "Hamming.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
CShortLC::CShortLC() :
|
CDMRShortLC::CDMRShortLC() :
|
||||||
m_rawData(NULL),
|
m_rawData(NULL),
|
||||||
m_deInterData(NULL)
|
m_deInterData(NULL)
|
||||||
{
|
{
|
||||||
|
@ -33,14 +33,14 @@ m_deInterData(NULL)
|
||||||
m_deInterData = new bool[68U];
|
m_deInterData = new bool[68U];
|
||||||
}
|
}
|
||||||
|
|
||||||
CShortLC::~CShortLC()
|
CDMRShortLC::~CDMRShortLC()
|
||||||
{
|
{
|
||||||
delete[] m_rawData;
|
delete[] m_rawData;
|
||||||
delete[] m_deInterData;
|
delete[] m_deInterData;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The main decode function
|
// The main decode function
|
||||||
bool CShortLC::decode(const unsigned char* in, unsigned char* out)
|
bool CDMRShortLC::decode(const unsigned char* in, unsigned char* out)
|
||||||
{
|
{
|
||||||
assert(in != NULL);
|
assert(in != NULL);
|
||||||
assert(out != NULL);
|
assert(out != NULL);
|
||||||
|
@ -63,7 +63,7 @@ bool CShortLC::decode(const unsigned char* in, unsigned char* out)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The main encode function
|
// The main encode function
|
||||||
void CShortLC::encode(const unsigned char* in, unsigned char* out)
|
void CDMRShortLC::encode(const unsigned char* in, unsigned char* out)
|
||||||
{
|
{
|
||||||
assert(in != NULL);
|
assert(in != NULL);
|
||||||
assert(out != NULL);
|
assert(out != NULL);
|
||||||
|
@ -81,8 +81,10 @@ void CShortLC::encode(const unsigned char* in, unsigned char* out)
|
||||||
encodeExtractBinary(out);
|
encodeExtractBinary(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CShortLC::decodeExtractBinary(const unsigned char* in)
|
void CDMRShortLC::decodeExtractBinary(const unsigned char* in)
|
||||||
{
|
{
|
||||||
|
assert(in != NULL);
|
||||||
|
|
||||||
CUtils::byteToBitsBE(in[0U], m_rawData + 0U);
|
CUtils::byteToBitsBE(in[0U], m_rawData + 0U);
|
||||||
CUtils::byteToBitsBE(in[1U], m_rawData + 8U);
|
CUtils::byteToBitsBE(in[1U], m_rawData + 8U);
|
||||||
CUtils::byteToBitsBE(in[2U], m_rawData + 16U);
|
CUtils::byteToBitsBE(in[2U], m_rawData + 16U);
|
||||||
|
@ -95,7 +97,7 @@ void CShortLC::decodeExtractBinary(const unsigned char* in)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deinterleave the raw data
|
// Deinterleave the raw data
|
||||||
void CShortLC::decodeDeInterleave()
|
void CDMRShortLC::decodeDeInterleave()
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0U; i < 68U; i++)
|
for (unsigned int i = 0U; i < 68U; i++)
|
||||||
m_deInterData[i] = false;
|
m_deInterData[i] = false;
|
||||||
|
@ -111,7 +113,7 @@ void CShortLC::decodeDeInterleave()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check each row with a Hamming (17,12,3) code and each column with a parity bit
|
// Check each row with a Hamming (17,12,3) code and each column with a parity bit
|
||||||
bool CShortLC::decodeErrorCheck()
|
bool CDMRShortLC::decodeErrorCheck()
|
||||||
{
|
{
|
||||||
// Run through each of the 3 rows containing data
|
// Run through each of the 3 rows containing data
|
||||||
CHamming::decode17123(m_deInterData + 0U);
|
CHamming::decode17123(m_deInterData + 0U);
|
||||||
|
@ -129,8 +131,10 @@ bool CShortLC::decodeErrorCheck()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract the 36 bits of payload
|
// Extract the 36 bits of payload
|
||||||
void CShortLC::decodeExtractData(unsigned char* data) const
|
void CDMRShortLC::decodeExtractData(unsigned char* data) const
|
||||||
{
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
bool bData[40U];
|
bool bData[40U];
|
||||||
|
|
||||||
for (unsigned int i = 0U; i < 40U; i++)
|
for (unsigned int i = 0U; i < 40U; i++)
|
||||||
|
@ -154,8 +158,10 @@ void CShortLC::decodeExtractData(unsigned char* data) const
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract the 36 bits of payload
|
// Extract the 36 bits of payload
|
||||||
void CShortLC::encodeExtractData(const unsigned char* in) const
|
void CDMRShortLC::encodeExtractData(const unsigned char* in) const
|
||||||
{
|
{
|
||||||
|
assert(in != NULL);
|
||||||
|
|
||||||
bool bData[40U];
|
bool bData[40U];
|
||||||
CUtils::byteToBitsBE(in[0U], bData + 0U);
|
CUtils::byteToBitsBE(in[0U], bData + 0U);
|
||||||
CUtils::byteToBitsBE(in[1U], bData + 8U);
|
CUtils::byteToBitsBE(in[1U], bData + 8U);
|
||||||
|
@ -178,7 +184,7 @@ void CShortLC::encodeExtractData(const unsigned char* in) const
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check each row with a Hamming (17,12,3) code and each column with a parity bit
|
// Check each row with a Hamming (17,12,3) code and each column with a parity bit
|
||||||
void CShortLC::encodeErrorCheck()
|
void CDMRShortLC::encodeErrorCheck()
|
||||||
{
|
{
|
||||||
// Run through each of the 3 rows containing data
|
// Run through each of the 3 rows containing data
|
||||||
CHamming::encode17123(m_deInterData + 0U);
|
CHamming::encode17123(m_deInterData + 0U);
|
||||||
|
@ -191,7 +197,7 @@ void CShortLC::encodeErrorCheck()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interleave the raw data
|
// Interleave the raw data
|
||||||
void CShortLC::encodeInterleave()
|
void CDMRShortLC::encodeInterleave()
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0U; i < 72U; i++)
|
for (unsigned int i = 0U; i < 72U; i++)
|
||||||
m_rawData[i] = false;
|
m_rawData[i] = false;
|
||||||
|
@ -206,8 +212,10 @@ void CShortLC::encodeInterleave()
|
||||||
m_rawData[67U] = m_deInterData[67U];
|
m_rawData[67U] = m_deInterData[67U];
|
||||||
}
|
}
|
||||||
|
|
||||||
void CShortLC::encodeExtractBinary(unsigned char* data)
|
void CDMRShortLC::encodeExtractBinary(unsigned char* data)
|
||||||
{
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
CUtils::bitsToByteBE(m_rawData + 0U, data[0U]);
|
CUtils::bitsToByteBE(m_rawData + 0U, data[0U]);
|
||||||
CUtils::bitsToByteBE(m_rawData + 8U, data[1U]);
|
CUtils::bitsToByteBE(m_rawData + 8U, data[1U]);
|
||||||
CUtils::bitsToByteBE(m_rawData + 16U, data[2U]);
|
CUtils::bitsToByteBE(m_rawData + 16U, data[2U]);
|
|
@ -16,14 +16,14 @@
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if !defined(SHORTLC_H)
|
#if !defined(DMRSHORTLC_H)
|
||||||
#define SHORTLC_H
|
#define DMRSHORTLC_H
|
||||||
|
|
||||||
class CShortLC
|
class CDMRShortLC
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CShortLC();
|
CDMRShortLC();
|
||||||
~CShortLC();
|
~CDMRShortLC();
|
||||||
|
|
||||||
bool decode(const unsigned char* in, unsigned char* out);
|
bool decode(const unsigned char* in, unsigned char* out);
|
||||||
|
|
2069
DMRSlot.cpp
118
DMRSlot.h
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015-2019 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -19,10 +19,13 @@
|
||||||
#if !defined(DMRSlot_H)
|
#if !defined(DMRSlot_H)
|
||||||
#define DMRSlot_H
|
#define DMRSlot_H
|
||||||
|
|
||||||
#include "HomebrewDMRIPSC.h"
|
#include "RSSIInterpolator.h"
|
||||||
#include "StopWatch.h"
|
#include "DMREmbeddedData.h"
|
||||||
#include "EmbeddedLC.h"
|
#include "DMRNetwork.h"
|
||||||
|
#include "DMRTA.h"
|
||||||
#include "RingBuffer.h"
|
#include "RingBuffer.h"
|
||||||
|
#include "StopWatch.h"
|
||||||
|
#include "DMRLookup.h"
|
||||||
#include "AMBEFEC.h"
|
#include "AMBEFEC.h"
|
||||||
#include "DMRSlot.h"
|
#include "DMRSlot.h"
|
||||||
#include "DMRData.h"
|
#include "DMRData.h"
|
||||||
|
@ -30,67 +33,130 @@
|
||||||
#include "Defines.h"
|
#include "Defines.h"
|
||||||
#include "Timer.h"
|
#include "Timer.h"
|
||||||
#include "Modem.h"
|
#include "Modem.h"
|
||||||
#include "LC.h"
|
#include "DMRLC.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
enum ACTIVITY_TYPE {
|
||||||
|
ACTIVITY_NONE,
|
||||||
|
ACTIVITY_VOICE,
|
||||||
|
ACTIVITY_DATA,
|
||||||
|
ACTIVITY_CSBK,
|
||||||
|
ACTIVITY_EMERG
|
||||||
|
};
|
||||||
|
|
||||||
class CDMRSlot {
|
class CDMRSlot {
|
||||||
public:
|
public:
|
||||||
CDMRSlot(unsigned int slotNo, unsigned int timeout);
|
CDMRSlot(unsigned int slotNo, unsigned int timeout);
|
||||||
~CDMRSlot();
|
~CDMRSlot();
|
||||||
|
|
||||||
void writeModem(unsigned char* data);
|
bool writeModem(unsigned char* data, unsigned int len);
|
||||||
|
|
||||||
unsigned int readModem(unsigned char* data);
|
unsigned int readModem(unsigned char* data);
|
||||||
|
|
||||||
void writeNetwork(const CDMRData& data);
|
void writeNetwork(const CDMRData& data);
|
||||||
|
|
||||||
void clock(unsigned int ms);
|
void clock();
|
||||||
|
|
||||||
static void init(unsigned int colorCode, CModem* modem, CHomebrewDMRIPSC* network, IDisplay* display);
|
bool isBusy() const;
|
||||||
|
|
||||||
|
void enable(bool enabled);
|
||||||
|
|
||||||
|
static void init(unsigned int colorCode, bool embeddedLCOnly, bool dumpTAData, unsigned int callHang, CModem* modem, CDMRNetwork* network, CDisplay* display, bool duplex, CDMRLookup* lookup, CRSSIInterpolator* rssiMapper, unsigned int jitter, DMR_OVCM_TYPES ovcm);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned int m_slotNo;
|
unsigned int m_slotNo;
|
||||||
CRingBuffer<unsigned char> m_queue;
|
CRingBuffer<unsigned char> m_queue;
|
||||||
RPT_STATE m_state;
|
RPT_RF_STATE m_rfState;
|
||||||
CEmbeddedLC m_embeddedLC;
|
RPT_NET_STATE m_netState;
|
||||||
CLC* m_lc;
|
CDMREmbeddedData m_rfEmbeddedLC;
|
||||||
unsigned char m_seqNo;
|
CDMREmbeddedData* m_rfEmbeddedData;
|
||||||
unsigned char m_n;
|
unsigned int m_rfEmbeddedReadN;
|
||||||
unsigned char* m_lastFrame;
|
unsigned int m_rfEmbeddedWriteN;
|
||||||
|
unsigned char m_rfTalkerId;
|
||||||
|
CDMRTA m_rfTalkerAlias;
|
||||||
|
CDMREmbeddedData m_netEmbeddedLC;
|
||||||
|
CDMREmbeddedData* m_netEmbeddedData;
|
||||||
|
unsigned int m_netEmbeddedReadN;
|
||||||
|
unsigned int m_netEmbeddedWriteN;
|
||||||
|
unsigned char m_netTalkerId;
|
||||||
|
CDMRLC* m_rfLC;
|
||||||
|
CDMRLC* m_netLC;
|
||||||
|
unsigned char m_rfSeqNo;
|
||||||
|
unsigned char m_rfN;
|
||||||
|
unsigned char m_lastrfN;
|
||||||
|
unsigned char m_netN;
|
||||||
CTimer m_networkWatchdog;
|
CTimer m_networkWatchdog;
|
||||||
CTimer m_timeoutTimer;
|
CTimer m_rfTimeoutTimer;
|
||||||
|
CTimer m_netTimeoutTimer;
|
||||||
CTimer m_packetTimer;
|
CTimer m_packetTimer;
|
||||||
|
CStopWatch m_interval;
|
||||||
CStopWatch m_elapsed;
|
CStopWatch m_elapsed;
|
||||||
unsigned int m_frames;
|
unsigned int m_rfFrames;
|
||||||
unsigned int m_lost;
|
unsigned int m_netFrames;
|
||||||
|
unsigned int m_netLost;
|
||||||
CAMBEFEC m_fec;
|
CAMBEFEC m_fec;
|
||||||
unsigned int m_bits;
|
unsigned int m_rfBits;
|
||||||
unsigned int m_errs;
|
unsigned int m_netBits;
|
||||||
|
unsigned int m_rfErrs;
|
||||||
|
unsigned int m_netErrs;
|
||||||
|
bool m_rfTimeout;
|
||||||
|
bool m_netTimeout;
|
||||||
|
unsigned char* m_lastFrame;
|
||||||
|
bool m_lastFrameValid;
|
||||||
|
unsigned char m_rssi;
|
||||||
|
unsigned char m_maxRSSI;
|
||||||
|
unsigned char m_minRSSI;
|
||||||
|
unsigned int m_aveRSSI;
|
||||||
|
unsigned int m_rssiCount;
|
||||||
|
bool m_enabled;
|
||||||
FILE* m_fp;
|
FILE* m_fp;
|
||||||
|
|
||||||
static unsigned int m_colorCode;
|
static unsigned int m_colorCode;
|
||||||
|
|
||||||
|
static bool m_embeddedLCOnly;
|
||||||
|
static bool m_dumpTAData;
|
||||||
|
|
||||||
static CModem* m_modem;
|
static CModem* m_modem;
|
||||||
static CHomebrewDMRIPSC* m_network;
|
static CDMRNetwork* m_network;
|
||||||
static IDisplay* m_display;
|
static CDisplay* m_display;
|
||||||
|
static bool m_duplex;
|
||||||
|
static CDMRLookup* m_lookup;
|
||||||
|
static unsigned int m_hangCount;
|
||||||
|
static DMR_OVCM_TYPES m_ovcm;
|
||||||
|
|
||||||
|
static CRSSIInterpolator* m_rssiMapper;
|
||||||
|
|
||||||
|
static unsigned int m_jitterTime;
|
||||||
|
static unsigned int m_jitterSlots;
|
||||||
|
|
||||||
static unsigned char* m_idle;
|
static unsigned char* m_idle;
|
||||||
|
|
||||||
static FLCO m_flco1;
|
static FLCO m_flco1;
|
||||||
static unsigned char m_id1;
|
static unsigned char m_id1;
|
||||||
|
static ACTIVITY_TYPE m_activity1;
|
||||||
static FLCO m_flco2;
|
static FLCO m_flco2;
|
||||||
static unsigned char m_id2;
|
static unsigned char m_id2;
|
||||||
|
static ACTIVITY_TYPE m_activity2;
|
||||||
|
|
||||||
void writeQueue(const unsigned char* data);
|
void logGPSPosition(const unsigned char* data);
|
||||||
void writeNetwork(const unsigned char* data, unsigned char dataType);
|
|
||||||
|
|
||||||
void writeEndOfTransmission();
|
void writeQueueRF(const unsigned char* data);
|
||||||
|
void writeQueueNet(const unsigned char* data);
|
||||||
|
void writeNetworkRF(const unsigned char* data, unsigned char dataType, unsigned char errors = 0U);
|
||||||
|
void writeNetworkRF(const unsigned char* data, unsigned char dataType, FLCO flco, unsigned int srcId, unsigned int dstId, unsigned char errors = 0U);
|
||||||
|
|
||||||
|
void writeEndRF(bool writeEnd = false);
|
||||||
|
void writeEndNet(bool writeEnd = false);
|
||||||
|
|
||||||
bool openFile();
|
bool openFile();
|
||||||
bool writeFile(const unsigned char* data);
|
bool writeFile(const unsigned char* data);
|
||||||
void closeFile();
|
void closeFile();
|
||||||
|
|
||||||
void insertSilence(unsigned char seqNo);
|
bool insertSilence(const unsigned char* data, unsigned char seqNo);
|
||||||
|
void insertSilence(unsigned int count);
|
||||||
|
|
||||||
static void setShortLC(unsigned int slotNo, unsigned int id, FLCO flco = FLCO_GROUP);
|
static void setShortLC(unsigned int slotNo, unsigned int id, FLCO flco = FLCO_GROUP, ACTIVITY_TYPE type = ACTIVITY_NONE);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
92
DMRSlotType.cpp
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "DMRSlotType.h"
|
||||||
|
|
||||||
|
#include "Golay2087.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
CDMRSlotType::CDMRSlotType() :
|
||||||
|
m_colorCode(0U),
|
||||||
|
m_dataType(0U)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CDMRSlotType::~CDMRSlotType()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMRSlotType::putData(const unsigned char* data)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
unsigned char DMRSlotType[3U];
|
||||||
|
DMRSlotType[0U] = (data[12U] << 2) & 0xFCU;
|
||||||
|
DMRSlotType[0U] |= (data[13U] >> 6) & 0x03U;
|
||||||
|
|
||||||
|
DMRSlotType[1U] = (data[13U] << 2) & 0xC0U;
|
||||||
|
DMRSlotType[1U] |= (data[19U] << 2) & 0x3CU;
|
||||||
|
DMRSlotType[1U] |= (data[20U] >> 6) & 0x03U;
|
||||||
|
|
||||||
|
DMRSlotType[2U] = (data[20U] << 2) & 0xF0U;
|
||||||
|
|
||||||
|
unsigned char code = CGolay2087::decode(DMRSlotType);
|
||||||
|
|
||||||
|
m_colorCode = (code >> 4) & 0x0FU;
|
||||||
|
m_dataType = (code >> 0) & 0x0FU;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMRSlotType::getData(unsigned char* data) const
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
unsigned char DMRSlotType[3U];
|
||||||
|
DMRSlotType[0U] = (m_colorCode << 4) & 0xF0U;
|
||||||
|
DMRSlotType[0U] |= (m_dataType << 0) & 0x0FU;
|
||||||
|
DMRSlotType[1U] = 0x00U;
|
||||||
|
DMRSlotType[2U] = 0x00U;
|
||||||
|
|
||||||
|
CGolay2087::encode(DMRSlotType);
|
||||||
|
|
||||||
|
data[12U] = (data[12U] & 0xC0U) | ((DMRSlotType[0U] >> 2) & 0x3FU);
|
||||||
|
data[13U] = (data[13U] & 0x0FU) | ((DMRSlotType[0U] << 6) & 0xC0U) | ((DMRSlotType[1U] >> 2) & 0x30U);
|
||||||
|
data[19U] = (data[19U] & 0xF0U) | ((DMRSlotType[1U] >> 2) & 0x0FU);
|
||||||
|
data[20U] = (data[20U] & 0x03U) | ((DMRSlotType[1U] << 6) & 0xC0U) | ((DMRSlotType[2U] >> 2) & 0x3CU);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char CDMRSlotType::getColorCode() const
|
||||||
|
{
|
||||||
|
return m_colorCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMRSlotType::setColorCode(unsigned char code)
|
||||||
|
{
|
||||||
|
m_colorCode = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char CDMRSlotType::getDataType() const
|
||||||
|
{
|
||||||
|
return m_dataType;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMRSlotType::setDataType(unsigned char type)
|
||||||
|
{
|
||||||
|
m_dataType = type;
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -16,14 +16,14 @@
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if !defined(SLOTTYPE_H)
|
#if !defined(DMRSLOTTYPE_H)
|
||||||
#define SLOTTYPE_H
|
#define DMRSLOTTYPE_H
|
||||||
|
|
||||||
class CSlotType
|
class CDMRSlotType
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CSlotType();
|
CDMRSlotType();
|
||||||
~CSlotType();
|
~CDMRSlotType();
|
||||||
|
|
||||||
void putData(const unsigned char* data);
|
void putData(const unsigned char* data);
|
||||||
void getData(unsigned char* data) const;
|
void getData(unsigned char* data) const;
|
155
DMRSync.cpp
|
@ -1,155 +0,0 @@
|
||||||
/*
|
|
||||||
* 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;
|
|
||||||
}
|
|
126
DMRTA.cpp
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016,2017,2018 Jonathan Naylor, G4KLX
|
||||||
|
* Copyright (C) 2018 by Shawn Chain, BG5HHP
|
||||||
|
*
|
||||||
|
* 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 "DMRTA.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
CDMRTA::CDMRTA() :
|
||||||
|
m_TA(),
|
||||||
|
m_buf()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CDMRTA::~CDMRTA()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMRTA::add(unsigned int blockId, const unsigned char* data, unsigned int len)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
if (blockId > 3) {
|
||||||
|
// invalid block id
|
||||||
|
reset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int offset = blockId * 7;
|
||||||
|
|
||||||
|
if (offset + len >= sizeof(m_buf)) {
|
||||||
|
// buffer overflow
|
||||||
|
reset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
::memcpy(m_buf + offset, data, len);
|
||||||
|
|
||||||
|
return decodeTA();
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned char* CDMRTA::get()
|
||||||
|
{
|
||||||
|
return (unsigned char*)m_TA;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMRTA::reset()
|
||||||
|
{
|
||||||
|
::memset(m_TA, 0, sizeof(m_TA));
|
||||||
|
::memset(m_buf, 0, sizeof(m_buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMRTA::decodeTA()
|
||||||
|
{
|
||||||
|
unsigned char *b;
|
||||||
|
unsigned char c;
|
||||||
|
int j;
|
||||||
|
unsigned int i, t1, t2;
|
||||||
|
|
||||||
|
unsigned char* talkerAlias = m_buf;
|
||||||
|
|
||||||
|
unsigned int TAformat = (talkerAlias[0] >> 6U) & 0x03U;
|
||||||
|
unsigned int TAsize = (talkerAlias[0] >> 1U) & 0x1FU;
|
||||||
|
::strcpy(m_TA, "(could not decode)");
|
||||||
|
|
||||||
|
switch (TAformat) {
|
||||||
|
case 0U: // 7 bit
|
||||||
|
::memset(m_TA, 0, sizeof(m_TA));
|
||||||
|
b = &talkerAlias[0];
|
||||||
|
t1 = 0U; t2 = 0U; c = 0U;
|
||||||
|
for (i = 0U; (i < 32U) && (t2 < TAsize); i++) {
|
||||||
|
for (j = 7; j >= 0; j--) {
|
||||||
|
c = (c << 1U) | (b[i] >> j);
|
||||||
|
if (++t1 == 7U) {
|
||||||
|
if (i > 0U)
|
||||||
|
m_TA[t2++] = c & 0x7FU;
|
||||||
|
|
||||||
|
t1 = 0U;
|
||||||
|
c = 0U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_TA[TAsize] = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1U: // ISO 8 bit
|
||||||
|
case 2U: // UTF8
|
||||||
|
::memcpy(m_TA, talkerAlias + 1U, sizeof(m_TA));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3U: // UTF16 poor man's conversion
|
||||||
|
t2=0;
|
||||||
|
::memset(&m_TA, 0, sizeof(m_TA));
|
||||||
|
for (i = 0U; (i < 15U) && (t2 < TAsize); i++) {
|
||||||
|
if (talkerAlias[2U * i + 1U] == 0)
|
||||||
|
m_TA[t2++] = talkerAlias[2U * i + 2U];
|
||||||
|
else
|
||||||
|
m_TA[t2++] = '?';
|
||||||
|
}
|
||||||
|
m_TA[TAsize] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t TAlen = ::strlen(m_TA);
|
||||||
|
LogMessage("DMR Talker Alias (Data Format %u, Received %u/%u char): '%s'", TAformat, TAlen, TAsize, m_TA);
|
||||||
|
|
||||||
|
if (TAlen > TAsize) {
|
||||||
|
if (TAlen < 29U)
|
||||||
|
strcat(m_TA, " ?");
|
||||||
|
else
|
||||||
|
strcpy(m_TA + 28U, " ?");
|
||||||
|
}
|
||||||
|
|
||||||
|
return TAlen >= TAsize;
|
||||||
|
}
|
35
DMRTA.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015,2016,2017,2018 Jonathan Naylor, G4KLX
|
||||||
|
* Copyright (C) 2018 by Shawn Chain, BG5HHP
|
||||||
|
*
|
||||||
|
* 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 DMRTA_H
|
||||||
|
#define DMRTA_H
|
||||||
|
|
||||||
|
class CDMRTA {
|
||||||
|
public:
|
||||||
|
CDMRTA();
|
||||||
|
~CDMRTA();
|
||||||
|
|
||||||
|
bool add(unsigned int blockId, const unsigned char* data, unsigned int len);
|
||||||
|
const unsigned char* get();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool decodeTA();
|
||||||
|
|
||||||
|
private:
|
||||||
|
char m_TA[32];
|
||||||
|
unsigned char m_buf[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
374
DMRTrellis.cpp
Normal file
|
@ -0,0 +1,374 @@
|
||||||
|
/*
|
||||||
|
* 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; 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 "DMRTrellis.h"
|
||||||
|
#include "DMRDefines.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
const unsigned int INTERLEAVE_TABLE[] = {
|
||||||
|
0U, 1U, 8U, 9U, 16U, 17U, 24U, 25U, 32U, 33U, 40U, 41U, 48U, 49U, 56U, 57U, 64U, 65U, 72U, 73U, 80U, 81U, 88U, 89U, 96U, 97U,
|
||||||
|
2U, 3U, 10U, 11U, 18U, 19U, 26U, 27U, 34U, 35U, 42U, 43U, 50U, 51U, 58U, 59U, 66U, 67U, 74U, 75U, 82U, 83U, 90U, 91U,
|
||||||
|
4U, 5U, 12U, 13U, 20U, 21U, 28U, 29U, 36U, 37U, 44U, 45U, 52U, 53U, 60U, 61U, 68U, 69U, 76U, 77U, 84U, 85U, 92U, 93U,
|
||||||
|
6U, 7U, 14U, 15U, 22U, 23U, 30U, 31U, 38U, 39U, 46U, 47U, 54U, 55U, 62U, 63U, 70U, 71U, 78U, 79U, 86U, 87U, 94U, 95U};
|
||||||
|
|
||||||
|
const unsigned char ENCODE_TABLE[] = {
|
||||||
|
0U, 8U, 4U, 12U, 2U, 10U, 6U, 14U,
|
||||||
|
4U, 12U, 2U, 10U, 6U, 14U, 0U, 8U,
|
||||||
|
1U, 9U, 5U, 13U, 3U, 11U, 7U, 15U,
|
||||||
|
5U, 13U, 3U, 11U, 7U, 15U, 1U, 9U,
|
||||||
|
3U, 11U, 7U, 15U, 1U, 9U, 5U, 13U,
|
||||||
|
7U, 15U, 1U, 9U, 5U, 13U, 3U, 11U,
|
||||||
|
2U, 10U, 6U, 14U, 0U, 8U, 4U, 12U,
|
||||||
|
6U, 14U, 0U, 8U, 4U, 12U, 2U, 10U};
|
||||||
|
|
||||||
|
const unsigned char BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U};
|
||||||
|
|
||||||
|
#define WRITE_BIT(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7])
|
||||||
|
#define READ_BIT(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
|
||||||
|
|
||||||
|
CDMRTrellis::CDMRTrellis()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CDMRTrellis::~CDMRTrellis()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMRTrellis::decode(const unsigned char* data, unsigned char* payload)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
assert(payload != NULL);
|
||||||
|
|
||||||
|
signed char dibits[98U];
|
||||||
|
deinterleave(data, dibits);
|
||||||
|
|
||||||
|
unsigned char points[49U];
|
||||||
|
dibitsToPoints(dibits, points);
|
||||||
|
|
||||||
|
// Check the original code
|
||||||
|
unsigned char tribits[49U];
|
||||||
|
unsigned int failPos = checkCode(points, tribits);
|
||||||
|
if (failPos == 999U) {
|
||||||
|
tribitsToBits(tribits, payload);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char savePoints[49U];
|
||||||
|
for (unsigned int i = 0U; i < 49U; i++)
|
||||||
|
savePoints[i] = points[i];
|
||||||
|
|
||||||
|
bool ret = fixCode(points, failPos, payload);
|
||||||
|
if (ret)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (failPos == 0U)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Backtrack one place for a last go
|
||||||
|
return fixCode(savePoints, failPos - 1U, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMRTrellis::encode(const unsigned char* payload, unsigned char* data)
|
||||||
|
{
|
||||||
|
assert(payload != NULL);
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
unsigned char tribits[49U];
|
||||||
|
bitsToTribits(payload, tribits);
|
||||||
|
|
||||||
|
unsigned char points[49U];
|
||||||
|
unsigned char state = 0U;
|
||||||
|
|
||||||
|
for (unsigned int i = 0U; i < 49U; i++) {
|
||||||
|
unsigned char tribit = tribits[i];
|
||||||
|
|
||||||
|
points[i] = ENCODE_TABLE[state * 8U + tribit];
|
||||||
|
|
||||||
|
state = tribit;
|
||||||
|
}
|
||||||
|
|
||||||
|
signed char dibits[98U];
|
||||||
|
pointsToDibits(points, dibits);
|
||||||
|
|
||||||
|
interleave(dibits, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMRTrellis::deinterleave(const unsigned char* data, signed char* dibits) const
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0U; i < 98U; i++) {
|
||||||
|
unsigned int n = i * 2U + 0U;
|
||||||
|
if (n >= 98U) n += 68U;
|
||||||
|
bool b1 = READ_BIT(data, n) != 0x00U;
|
||||||
|
|
||||||
|
n = i * 2U + 1U;
|
||||||
|
if (n >= 98U) n += 68U;
|
||||||
|
bool b2 = READ_BIT(data, n) != 0x00U;
|
||||||
|
|
||||||
|
signed char dibit;
|
||||||
|
if (!b1 && b2)
|
||||||
|
dibit = +3;
|
||||||
|
else if (!b1 && !b2)
|
||||||
|
dibit = +1;
|
||||||
|
else if (b1 && !b2)
|
||||||
|
dibit = -1;
|
||||||
|
else
|
||||||
|
dibit = -3;
|
||||||
|
|
||||||
|
n = INTERLEAVE_TABLE[i];
|
||||||
|
dibits[n] = dibit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMRTrellis::interleave(const signed char* dibits, unsigned char* data) const
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0U; i < 98U; i++) {
|
||||||
|
unsigned int n = INTERLEAVE_TABLE[i];
|
||||||
|
|
||||||
|
bool b1, b2;
|
||||||
|
switch (dibits[n]) {
|
||||||
|
case +3:
|
||||||
|
b1 = false;
|
||||||
|
b2 = true;
|
||||||
|
break;
|
||||||
|
case +1:
|
||||||
|
b1 = false;
|
||||||
|
b2 = false;
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
b1 = true;
|
||||||
|
b2 = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
b1 = true;
|
||||||
|
b2 = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = i * 2U + 0U;
|
||||||
|
if (n >= 98U) n += 68U;
|
||||||
|
WRITE_BIT(data, n, b1);
|
||||||
|
|
||||||
|
n = i * 2U + 1U;
|
||||||
|
if (n >= 98U) n += 68U;
|
||||||
|
WRITE_BIT(data, n, b2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMRTrellis::dibitsToPoints(const signed char* dibits, unsigned char* points) const
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0U; i < 49U; i++) {
|
||||||
|
if (dibits[i * 2U + 0U] == +1 && dibits[i * 2U + 1U] == -1)
|
||||||
|
points[i] = 0U;
|
||||||
|
else if (dibits[i * 2U + 0U] == -1 && dibits[i * 2U + 1U] == -1)
|
||||||
|
points[i] = 1U;
|
||||||
|
else if (dibits[i * 2U + 0U] == +3 && dibits[i * 2U + 1U] == -3)
|
||||||
|
points[i] = 2U;
|
||||||
|
else if (dibits[i * 2U + 0U] == -3 && dibits[i * 2U + 1U] == -3)
|
||||||
|
points[i] = 3U;
|
||||||
|
else if (dibits[i * 2U + 0U] == -3 && dibits[i * 2U + 1U] == -1)
|
||||||
|
points[i] = 4U;
|
||||||
|
else if (dibits[i * 2U + 0U] == +3 && dibits[i * 2U + 1U] == -1)
|
||||||
|
points[i] = 5U;
|
||||||
|
else if (dibits[i * 2U + 0U] == -1 && dibits[i * 2U + 1U] == -3)
|
||||||
|
points[i] = 6U;
|
||||||
|
else if (dibits[i * 2U + 0U] == +1 && dibits[i * 2U + 1U] == -3)
|
||||||
|
points[i] = 7U;
|
||||||
|
else if (dibits[i * 2U + 0U] == -3 && dibits[i * 2U + 1U] == +3)
|
||||||
|
points[i] = 8U;
|
||||||
|
else if (dibits[i * 2U + 0U] == +3 && dibits[i * 2U + 1U] == +3)
|
||||||
|
points[i] = 9U;
|
||||||
|
else if (dibits[i * 2U + 0U] == -1 && dibits[i * 2U + 1U] == +1)
|
||||||
|
points[i] = 10U;
|
||||||
|
else if (dibits[i * 2U + 0U] == +1 && dibits[i * 2U + 1U] == +1)
|
||||||
|
points[i] = 11U;
|
||||||
|
else if (dibits[i * 2U + 0U] == +1 && dibits[i * 2U + 1U] == +3)
|
||||||
|
points[i] = 12U;
|
||||||
|
else if (dibits[i * 2U + 0U] == -1 && dibits[i * 2U + 1U] == +3)
|
||||||
|
points[i] = 13U;
|
||||||
|
else if (dibits[i * 2U + 0U] == +3 && dibits[i * 2U + 1U] == +1)
|
||||||
|
points[i] = 14U;
|
||||||
|
else if (dibits[i * 2U + 0U] == -3 && dibits[i * 2U + 1U] == +1)
|
||||||
|
points[i] = 15U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMRTrellis::pointsToDibits(const unsigned char* points, signed char* dibits) const
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0U; i < 49U; i++) {
|
||||||
|
switch (points[i]) {
|
||||||
|
case 0U:
|
||||||
|
dibits[i * 2U + 0U] = +1;
|
||||||
|
dibits[i * 2U + 1U] = -1;
|
||||||
|
break;
|
||||||
|
case 1U:
|
||||||
|
dibits[i * 2U + 0U] = -1;
|
||||||
|
dibits[i * 2U + 1U] = -1;
|
||||||
|
break;
|
||||||
|
case 2U:
|
||||||
|
dibits[i * 2U + 0U] = +3;
|
||||||
|
dibits[i * 2U + 1U] = -3;
|
||||||
|
break;
|
||||||
|
case 3U:
|
||||||
|
dibits[i * 2U + 0U] = -3;
|
||||||
|
dibits[i * 2U + 1U] = -3;
|
||||||
|
break;
|
||||||
|
case 4U:
|
||||||
|
dibits[i * 2U + 0U] = -3;
|
||||||
|
dibits[i * 2U + 1U] = -1;
|
||||||
|
break;
|
||||||
|
case 5U:
|
||||||
|
dibits[i * 2U + 0U] = +3;
|
||||||
|
dibits[i * 2U + 1U] = -1;
|
||||||
|
break;
|
||||||
|
case 6U:
|
||||||
|
dibits[i * 2U + 0U] = -1;
|
||||||
|
dibits[i * 2U + 1U] = -3;
|
||||||
|
break;
|
||||||
|
case 7U:
|
||||||
|
dibits[i * 2U + 0U] = +1;
|
||||||
|
dibits[i * 2U + 1U] = -3;
|
||||||
|
break;
|
||||||
|
case 8U:
|
||||||
|
dibits[i * 2U + 0U] = -3;
|
||||||
|
dibits[i * 2U + 1U] = +3;
|
||||||
|
break;
|
||||||
|
case 9U:
|
||||||
|
dibits[i * 2U + 0U] = +3;
|
||||||
|
dibits[i * 2U + 1U] = +3;
|
||||||
|
break;
|
||||||
|
case 10U:
|
||||||
|
dibits[i * 2U + 0U] = -1;
|
||||||
|
dibits[i * 2U + 1U] = +1;
|
||||||
|
break;
|
||||||
|
case 11U:
|
||||||
|
dibits[i * 2U + 0U] = +1;
|
||||||
|
dibits[i * 2U + 1U] = +1;
|
||||||
|
break;
|
||||||
|
case 12U:
|
||||||
|
dibits[i * 2U + 0U] = +1;
|
||||||
|
dibits[i * 2U + 1U] = +3;
|
||||||
|
break;
|
||||||
|
case 13U:
|
||||||
|
dibits[i * 2U + 0U] = -1;
|
||||||
|
dibits[i * 2U + 1U] = +3;
|
||||||
|
break;
|
||||||
|
case 14U:
|
||||||
|
dibits[i * 2U + 0U] = +3;
|
||||||
|
dibits[i * 2U + 1U] = +1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dibits[i * 2U + 0U] = -3;
|
||||||
|
dibits[i * 2U + 1U] = +1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMRTrellis::bitsToTribits(const unsigned char* payload, unsigned char* tribits) const
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0U; i < 48U; i++) {
|
||||||
|
unsigned int n = 143U - i * 3U;
|
||||||
|
|
||||||
|
bool b1 = READ_BIT(payload, n) != 0x00U;
|
||||||
|
n--;
|
||||||
|
bool b2 = READ_BIT(payload, n) != 0x00U;
|
||||||
|
n--;
|
||||||
|
bool b3 = READ_BIT(payload, n) != 0x00U;
|
||||||
|
|
||||||
|
unsigned char tribit = 0U;
|
||||||
|
tribit |= b1 ? 4U : 0U;
|
||||||
|
tribit |= b2 ? 2U : 0U;
|
||||||
|
tribit |= b3 ? 1U : 0U;
|
||||||
|
|
||||||
|
tribits[i] = tribit;
|
||||||
|
}
|
||||||
|
|
||||||
|
tribits[48U] = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMRTrellis::tribitsToBits(const unsigned char* tribits, unsigned char* payload) const
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0U; i < 48U; i++) {
|
||||||
|
unsigned char tribit = tribits[i];
|
||||||
|
|
||||||
|
bool b1 = (tribit & 0x04U) == 0x04U;
|
||||||
|
bool b2 = (tribit & 0x02U) == 0x02U;
|
||||||
|
bool b3 = (tribit & 0x01U) == 0x01U;
|
||||||
|
|
||||||
|
unsigned int n = 143U - i * 3U;
|
||||||
|
|
||||||
|
WRITE_BIT(payload, n, b1);
|
||||||
|
n--;
|
||||||
|
WRITE_BIT(payload, n, b2);
|
||||||
|
n--;
|
||||||
|
WRITE_BIT(payload, n, b3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMRTrellis::fixCode(unsigned char* points, unsigned int failPos, unsigned char* payload) const
|
||||||
|
{
|
||||||
|
for (unsigned j = 0U; j < 20U; j++) {
|
||||||
|
unsigned int bestPos = 0U;
|
||||||
|
unsigned int bestVal = 0U;
|
||||||
|
|
||||||
|
for (unsigned int i = 0U; i < 16U; i++) {
|
||||||
|
points[failPos] = i;
|
||||||
|
|
||||||
|
unsigned char tribits[49U];
|
||||||
|
unsigned int pos = checkCode(points, tribits);
|
||||||
|
if (pos == 999U) {
|
||||||
|
tribitsToBits(tribits, payload);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos > bestPos) {
|
||||||
|
bestPos = pos;
|
||||||
|
bestVal = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
points[failPos] = bestVal;
|
||||||
|
failPos = bestPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CDMRTrellis::checkCode(const unsigned char* points, unsigned char* tribits) const
|
||||||
|
{
|
||||||
|
unsigned char state = 0U;
|
||||||
|
|
||||||
|
for (unsigned int i = 0U; i < 49U; i++) {
|
||||||
|
tribits[i] = 9U;
|
||||||
|
|
||||||
|
for (unsigned int j = 0U; j < 8U; j++) {
|
||||||
|
if (points[i] == ENCODE_TABLE[state * 8U + j]) {
|
||||||
|
tribits[i] = j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tribits[i] == 9U)
|
||||||
|
return i;
|
||||||
|
|
||||||
|
state = tribits[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tribits[48U] != 0U)
|
||||||
|
return 48U;
|
||||||
|
|
||||||
|
return 999U;
|
||||||
|
}
|
36
DMRTrellis.h
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* 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; 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 DMRTrellis_H
|
||||||
|
#define DMRTrellis_H
|
||||||
|
|
||||||
|
class CDMRTrellis {
|
||||||
|
public:
|
||||||
|
CDMRTrellis();
|
||||||
|
~CDMRTrellis();
|
||||||
|
|
||||||
|
bool decode(const unsigned char* data, unsigned char* payload);
|
||||||
|
void encode(const unsigned char* payload, unsigned char* data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void deinterleave(const unsigned char* in, signed char* dibits) const;
|
||||||
|
void interleave(const signed char* dibits, unsigned char* out) const;
|
||||||
|
void dibitsToPoints(const signed char* dibits, unsigned char* points) const;
|
||||||
|
void pointsToDibits(const unsigned char* points, signed char* dibits) const;
|
||||||
|
void bitsToTribits(const unsigned char* payload, unsigned char* tribits) const;
|
||||||
|
void tribitsToBits(const unsigned char* tribits, unsigned char* payload) const;
|
||||||
|
bool fixCode(unsigned char* points, unsigned int failPos, unsigned char* payload) const;
|
||||||
|
unsigned int checkCode(const unsigned char* points, unsigned char* tribits) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
32
DMRplus_startup_options.md
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
# DMRplus - Startup Options
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
This file is to give an overview over the Options-parameter in MMDVM.ini [DMR Network]-section.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
You can pull some conection-info at startup to the DMRplus-Network to define the behavior of TS1 and TS2 in DMR-mode.
|
||||||
|
An example of such a line would be following:
|
||||||
|
|
||||||
|
Options=StartRef=4013;RelinkTime=15;UserLink=1;TS1_1=262;TS1_2=1;TS1_3=20;TS1_4=110;TS1_5=270;
|
||||||
|
|
||||||
|
If an option is set, it overwrites the setting preset at the master, if an option is empty, it unsets a predefined setting from
|
||||||
|
the master. If an option is not set, the default from the master would be taken over.
|
||||||
|
|
||||||
|
## What the parameters are about?
|
||||||
|
|
||||||
|
Here is a quick explaination about the options to be set:
|
||||||
|
|
||||||
|
* StartRef: This is the default reflector in TS2, in example: Refl. 4013
|
||||||
|
* RelinkTime: This is the time to fall back to the default-reflector if linked to another one and no local traffic is done,
|
||||||
|
not yet implemented, would come next
|
||||||
|
* UserLink: This defines, if users are allowed to link to another reflector (other than defined as startreflector)
|
||||||
|
* 1 = allow
|
||||||
|
* 0 = disallow
|
||||||
|
* TS1_1: This is the first of 5 talkgroups that could be set static, in example: TG262
|
||||||
|
* TS1_2: This is the second of 5 talkgroups that could be set static, in example: TG1
|
||||||
|
* TS1_3: This is the third of 5 talkgroups that could be set static, in example: TG20
|
||||||
|
* TS1_4: This is the fourth of 5 talkgroups that could be set static, in example: TG110
|
||||||
|
* TS1_5: This is the fifth of 5 talkgroups that could be set static, in example: TG270
|
||||||
|
|
||||||
|
---
|
||||||
|
Info created by DG9VH 2016-11-11
|
1266
DStarControl.cpp
Normal file
128
DStarControl.h
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015-2019 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(DStarControl_H)
|
||||||
|
#define DStarControl_H
|
||||||
|
|
||||||
|
#include "RSSIInterpolator.h"
|
||||||
|
#include "DStarNetwork.h"
|
||||||
|
#include "DStarSlowData.h"
|
||||||
|
#include "DStarDefines.h"
|
||||||
|
#include "DStarHeader.h"
|
||||||
|
#include "RingBuffer.h"
|
||||||
|
#include "StopWatch.h"
|
||||||
|
#include "AMBEFEC.h"
|
||||||
|
#include "Display.h"
|
||||||
|
#include "Defines.h"
|
||||||
|
#include "Timer.h"
|
||||||
|
#include "Modem.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class CDStarControl {
|
||||||
|
public:
|
||||||
|
CDStarControl(const std::string& callsign, const std::string& module, bool selfOnly, bool ackReply, unsigned int ackTime, bool ackMessage, bool errorReply, const std::vector<std::string>& blackList, CDStarNetwork* network, CDisplay* display, unsigned int timeout, bool duplex, bool remoteGateway, CRSSIInterpolator* rssiMapper);
|
||||||
|
~CDStarControl();
|
||||||
|
|
||||||
|
bool writeModem(unsigned char* data, unsigned int len);
|
||||||
|
|
||||||
|
unsigned int readModem(unsigned char* data);
|
||||||
|
|
||||||
|
void clock();
|
||||||
|
|
||||||
|
bool isBusy() const;
|
||||||
|
|
||||||
|
void enable(bool enabled);
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned char* m_callsign;
|
||||||
|
unsigned char* m_gateway;
|
||||||
|
bool m_selfOnly;
|
||||||
|
bool m_ackReply;
|
||||||
|
bool m_ackMessage;
|
||||||
|
bool m_errorReply;
|
||||||
|
bool m_remoteGateway;
|
||||||
|
std::vector<std::string> m_blackList;
|
||||||
|
CDStarNetwork* m_network;
|
||||||
|
CDisplay* m_display;
|
||||||
|
bool m_duplex;
|
||||||
|
CRingBuffer<unsigned char> m_queue;
|
||||||
|
CDStarHeader m_rfHeader;
|
||||||
|
CDStarHeader m_netHeader;
|
||||||
|
RPT_RF_STATE m_rfState;
|
||||||
|
RPT_NET_STATE m_netState;
|
||||||
|
bool m_net;
|
||||||
|
CDStarSlowData m_slowData;
|
||||||
|
unsigned char m_rfN;
|
||||||
|
unsigned char m_netN;
|
||||||
|
CTimer m_networkWatchdog;
|
||||||
|
CTimer m_rfTimeoutTimer;
|
||||||
|
CTimer m_netTimeoutTimer;
|
||||||
|
CTimer m_packetTimer;
|
||||||
|
CTimer m_ackTimer;
|
||||||
|
CTimer m_errTimer;
|
||||||
|
CStopWatch m_interval;
|
||||||
|
CStopWatch m_elapsed;
|
||||||
|
unsigned int m_rfFrames;
|
||||||
|
unsigned int m_netFrames;
|
||||||
|
unsigned int m_netLost;
|
||||||
|
CAMBEFEC m_fec;
|
||||||
|
unsigned int m_rfBits;
|
||||||
|
unsigned int m_netBits;
|
||||||
|
unsigned int m_rfErrs;
|
||||||
|
unsigned int m_netErrs;
|
||||||
|
unsigned char* m_lastFrame;
|
||||||
|
bool m_lastFrameValid;
|
||||||
|
CRSSIInterpolator* m_rssiMapper;
|
||||||
|
unsigned char m_rssi;
|
||||||
|
unsigned char m_maxRSSI;
|
||||||
|
unsigned char m_minRSSI;
|
||||||
|
unsigned int m_aveRSSI;
|
||||||
|
unsigned int m_rssiCount;
|
||||||
|
bool m_enabled;
|
||||||
|
FILE* m_fp;
|
||||||
|
|
||||||
|
void writeNetwork();
|
||||||
|
|
||||||
|
void writeQueueHeaderRF(const unsigned char* data);
|
||||||
|
void writeQueueDataRF(const unsigned char* data);
|
||||||
|
void writeQueueEOTRF();
|
||||||
|
void writeQueueHeaderNet(const unsigned char* data);
|
||||||
|
void writeQueueDataNet(const unsigned char* data);
|
||||||
|
void writeQueueEOTNet();
|
||||||
|
void writeNetworkHeaderRF(const unsigned char* data);
|
||||||
|
void writeNetworkDataRF(const unsigned char* data, unsigned int errors, bool end);
|
||||||
|
|
||||||
|
void writeEndRF();
|
||||||
|
void writeEndNet();
|
||||||
|
|
||||||
|
bool openFile();
|
||||||
|
bool writeFile(const unsigned char* data, unsigned int length);
|
||||||
|
void closeFile();
|
||||||
|
|
||||||
|
bool insertSilence(const unsigned char* data, unsigned char seqNo);
|
||||||
|
void insertSilence(unsigned int count);
|
||||||
|
|
||||||
|
void blankDTMF(unsigned char* data) const;
|
||||||
|
|
||||||
|
void sendAck();
|
||||||
|
void sendError();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2018,2019 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -19,10 +19,74 @@
|
||||||
#if !defined(DStarDefines_H)
|
#if !defined(DStarDefines_H)
|
||||||
#define DStarDefines_H
|
#define DStarDefines_H
|
||||||
|
|
||||||
|
#include "Defines.h"
|
||||||
|
|
||||||
const unsigned int DSTAR_HEADER_LENGTH_BYTES = 41U;
|
const unsigned int DSTAR_HEADER_LENGTH_BYTES = 41U;
|
||||||
const unsigned int DSTAR_FRAME_LENGTH_BYTES = 12U;
|
const unsigned int DSTAR_FRAME_LENGTH_BYTES = 12U;
|
||||||
|
|
||||||
// Check this
|
const unsigned char DSTAR_END_PATTERN_BYTES[] = { TAG_EOT, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xC8, 0x7A };
|
||||||
|
const unsigned int DSTAR_END_PATTERN_LENGTH_BYTES = 6U;
|
||||||
|
|
||||||
|
const unsigned char DSTAR_NULL_AMBE_DATA_BYTES[] = { 0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8 };
|
||||||
|
|
||||||
|
const unsigned char DSTAR_NULL_SLOW_SYNC_BYTES[] = { 0x55, 0x2D, 0x16 };
|
||||||
|
// Note that these are already scrambled, 0x66 0x66 0x66 otherwise
|
||||||
|
const unsigned char DSTAR_NULL_SLOW_DATA_BYTES[] = { 0x16, 0x29, 0xF5 };
|
||||||
|
|
||||||
|
const unsigned char DSTAR_NULL_FRAME_SYNC_BYTES[] = { TAG_DATA, 0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8, 0x55, 0x2D, 0x16 };
|
||||||
|
const unsigned char DSTAR_NULL_FRAME_DATA_BYTES[] = { TAG_DATA, 0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8, 0x16, 0x29, 0xF5 };
|
||||||
|
|
||||||
|
const unsigned char DSTAR_NULL_FRAME_DATA_SRAMBLED_BYTES[] = { 0xEEU, 0xC2U, 0xA1U, 0xC8U, 0x42U, 0x6EU, 0x52U, 0x51U, 0xC3U };
|
||||||
|
|
||||||
|
const unsigned int DSTAR_VOICE_FRAME_LENGTH_BYTES = 9U;
|
||||||
|
const unsigned int DSTAR_DATA_FRAME_LENGTH_BYTES = 3U;
|
||||||
|
|
||||||
|
const unsigned int DSTAR_LONG_CALLSIGN_LENGTH = 8U;
|
||||||
|
const unsigned int DSTAR_SHORT_CALLSIGN_LENGTH = 4U;
|
||||||
|
|
||||||
|
const unsigned char DSTAR_SLOW_DATA_TYPE_MASK = 0xF0U;
|
||||||
|
const unsigned char DSTAR_SLOW_DATA_TYPE_GPSDATA = 0x30U;
|
||||||
|
const unsigned char DSTAR_SLOW_DATA_TYPE_TEXT = 0x40U;
|
||||||
|
const unsigned char DSTAR_SLOW_DATA_TYPE_HEADER = 0x50U;
|
||||||
|
const unsigned char DSTAR_SLOW_DATA_TYPE_FAST_DATA1 = 0x80U;
|
||||||
|
const unsigned char DSTAR_SLOW_DATA_TYPE_FAST_DATA2 = 0x90U;
|
||||||
|
const unsigned char DSTAR_SLOW_DATA_TYPE_SQUELCH = 0xC0U;
|
||||||
|
const unsigned char DSTAR_SLOW_DATA_LENGTH_MASK = 0x0FU;
|
||||||
|
|
||||||
|
const unsigned char DSTAR_SCRAMBLER_BYTES[] = { 0x70U, 0x4FU, 0x93U, 0x40U, 0x64U, 0x74U, 0x6DU, 0x30U, 0x2BU };
|
||||||
|
|
||||||
|
const unsigned char DSTAR_DATA_MASK = 0x80U;
|
||||||
|
const unsigned char DSTAR_REPEATER_MASK = 0x40U;
|
||||||
|
const unsigned char DSTAR_INTERRUPTED_MASK = 0x20U;
|
||||||
|
const unsigned char DSTAR_CONTROL_SIGNAL_MASK = 0x10U;
|
||||||
|
const unsigned char DSTAR_URGENT_MASK = 0x08U;
|
||||||
|
const unsigned char DSTAR_REPEATER_CONTROL = 0x07U;
|
||||||
|
const unsigned char DSTAR_AUTO_REPLY = 0x06U;
|
||||||
|
const unsigned char DSTAR_RESEND_REQUESTED = 0x04U;
|
||||||
|
const unsigned char DSTAR_ACK_FLAG = 0x03U;
|
||||||
|
const unsigned char DSTAR_NO_RESPONSE = 0x02U;
|
||||||
|
const unsigned char DSTAR_RELAY_UNAVAILABLE = 0x01U;
|
||||||
|
|
||||||
const unsigned char DSTAR_SYNC_BYTES[] = {0x55U, 0x2DU, 0x16U};
|
const unsigned char DSTAR_SYNC_BYTES[] = {0x55U, 0x2DU, 0x16U};
|
||||||
|
|
||||||
|
const unsigned char DSTAR_DTMF_MASK[] = { 0x82U, 0x08U, 0x20U, 0x82U, 0x00U, 0x00U, 0x82U, 0x00U, 0x00U };
|
||||||
|
const unsigned char DSTAR_DTMF_SIG[] = { 0x82U, 0x08U, 0x20U, 0x82U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U };
|
||||||
|
|
||||||
|
const unsigned int DSTAR_FRAME_TIME = 20U;
|
||||||
|
|
||||||
|
enum LINK_STATUS {
|
||||||
|
LS_NONE,
|
||||||
|
LS_PENDING_IRCDDB,
|
||||||
|
LS_LINKING_LOOPBACK,
|
||||||
|
LS_LINKING_DEXTRA,
|
||||||
|
LS_LINKING_DPLUS,
|
||||||
|
LS_LINKING_DCS,
|
||||||
|
LS_LINKING_CCS,
|
||||||
|
LS_LINKED_LOOPBACK,
|
||||||
|
LS_LINKED_DEXTRA,
|
||||||
|
LS_LINKED_DPLUS,
|
||||||
|
LS_LINKED_DCS,
|
||||||
|
LS_LINKED_CCS
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,74 +0,0 @@
|
||||||
/*
|
|
||||||
* 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);
|
|
||||||
}
|
|
165
DStarHeader.cpp
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
/*
|
||||||
|
* 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 "DStarDefines.h"
|
||||||
|
#include "DStarHeader.h"
|
||||||
|
#include "CRC.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
CDStarHeader::CDStarHeader(const unsigned char* header) :
|
||||||
|
m_header(NULL)
|
||||||
|
{
|
||||||
|
assert(header != NULL);
|
||||||
|
|
||||||
|
m_header = new unsigned char[DSTAR_HEADER_LENGTH_BYTES];
|
||||||
|
|
||||||
|
::memcpy(m_header, header, DSTAR_HEADER_LENGTH_BYTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
CDStarHeader::CDStarHeader() :
|
||||||
|
m_header(NULL)
|
||||||
|
{
|
||||||
|
m_header = new unsigned char[DSTAR_HEADER_LENGTH_BYTES];
|
||||||
|
|
||||||
|
::memset(m_header, ' ', DSTAR_HEADER_LENGTH_BYTES);
|
||||||
|
|
||||||
|
m_header[0U] = 0x00U;
|
||||||
|
m_header[1U] = 0x00U;
|
||||||
|
m_header[2U] = 0x00U;
|
||||||
|
}
|
||||||
|
|
||||||
|
CDStarHeader::~CDStarHeader()
|
||||||
|
{
|
||||||
|
delete[] m_header;
|
||||||
|
}
|
||||||
|
|
||||||
|
CDStarHeader& CDStarHeader::operator=(const CDStarHeader& header)
|
||||||
|
{
|
||||||
|
if (&header != this)
|
||||||
|
::memcpy(m_header, header.m_header, DSTAR_HEADER_LENGTH_BYTES);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDStarHeader::isRepeater() const
|
||||||
|
{
|
||||||
|
return (m_header[0U] & DSTAR_REPEATER_MASK) == DSTAR_REPEATER_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDStarHeader::setRepeater(bool on)
|
||||||
|
{
|
||||||
|
if (on)
|
||||||
|
m_header[0U] |= DSTAR_REPEATER_MASK;
|
||||||
|
else
|
||||||
|
m_header[0U] &= ~DSTAR_REPEATER_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDStarHeader::isDataPacket() const
|
||||||
|
{
|
||||||
|
return (m_header[0U] & DSTAR_DATA_MASK) == DSTAR_DATA_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDStarHeader::setUnavailable(bool on)
|
||||||
|
{
|
||||||
|
if (on)
|
||||||
|
m_header[0U] |= DSTAR_RELAY_UNAVAILABLE;
|
||||||
|
else
|
||||||
|
m_header[0U] &= ~DSTAR_RELAY_UNAVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDStarHeader::getMyCall1(unsigned char* call1) const
|
||||||
|
{
|
||||||
|
assert(call1 != NULL);
|
||||||
|
|
||||||
|
::memcpy(call1, m_header + 27U, DSTAR_LONG_CALLSIGN_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDStarHeader::getMyCall2(unsigned char* call2) const
|
||||||
|
{
|
||||||
|
assert(call2 != NULL);
|
||||||
|
|
||||||
|
::memcpy(call2, m_header + 35U, DSTAR_SHORT_CALLSIGN_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDStarHeader::setMyCall1(const unsigned char* call1)
|
||||||
|
{
|
||||||
|
assert(call1 != NULL);
|
||||||
|
|
||||||
|
::memcpy(m_header + 27U, call1, DSTAR_LONG_CALLSIGN_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDStarHeader::setMyCall2(const unsigned char* call2)
|
||||||
|
{
|
||||||
|
assert(call2 != NULL);
|
||||||
|
|
||||||
|
::memcpy(m_header + 35U, call2, DSTAR_SHORT_CALLSIGN_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDStarHeader::getRPTCall1(unsigned char* call1) const
|
||||||
|
{
|
||||||
|
assert(call1 != NULL);
|
||||||
|
|
||||||
|
::memcpy(call1, m_header + 11U, DSTAR_LONG_CALLSIGN_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDStarHeader::getRPTCall2(unsigned char* call2) const
|
||||||
|
{
|
||||||
|
assert(call2 != NULL);
|
||||||
|
|
||||||
|
::memcpy(call2, m_header + 3U, DSTAR_LONG_CALLSIGN_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDStarHeader::setRPTCall1(const unsigned char* call1)
|
||||||
|
{
|
||||||
|
assert(call1 != NULL);
|
||||||
|
|
||||||
|
::memcpy(m_header + 11U, call1, DSTAR_LONG_CALLSIGN_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDStarHeader::setRPTCall2(const unsigned char* call2)
|
||||||
|
{
|
||||||
|
assert(call2 != NULL);
|
||||||
|
|
||||||
|
::memcpy(m_header + 3U, call2, DSTAR_LONG_CALLSIGN_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDStarHeader::getYourCall(unsigned char* call) const
|
||||||
|
{
|
||||||
|
assert(call != NULL);
|
||||||
|
|
||||||
|
::memcpy(call, m_header + 19U, DSTAR_LONG_CALLSIGN_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDStarHeader::setYourCall(const unsigned char* call)
|
||||||
|
{
|
||||||
|
assert(call != NULL);
|
||||||
|
|
||||||
|
::memcpy(m_header + 19U, call, DSTAR_LONG_CALLSIGN_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDStarHeader::get(unsigned char* header) const
|
||||||
|
{
|
||||||
|
assert(header != NULL);
|
||||||
|
|
||||||
|
::memcpy(header, m_header, DSTAR_HEADER_LENGTH_BYTES);
|
||||||
|
|
||||||
|
CCRC::addCCITT161(header, DSTAR_HEADER_LENGTH_BYTES);
|
||||||
|
}
|
58
DStarHeader.h
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DStarHeader_H
|
||||||
|
#define DStarHeader_H
|
||||||
|
|
||||||
|
class CDStarHeader {
|
||||||
|
public:
|
||||||
|
CDStarHeader(const unsigned char* header);
|
||||||
|
CDStarHeader();
|
||||||
|
~CDStarHeader();
|
||||||
|
|
||||||
|
bool isRepeater() const;
|
||||||
|
void setRepeater(bool on);
|
||||||
|
|
||||||
|
bool isDataPacket() const;
|
||||||
|
|
||||||
|
void setUnavailable(bool on);
|
||||||
|
|
||||||
|
void getMyCall1(unsigned char* call1) const;
|
||||||
|
void getMyCall2(unsigned char* call2) const;
|
||||||
|
|
||||||
|
void setMyCall1(const unsigned char* call1);
|
||||||
|
void setMyCall2(const unsigned char* call2);
|
||||||
|
|
||||||
|
void getRPTCall1(unsigned char* call1) const;
|
||||||
|
void getRPTCall2(unsigned char* call2) const;
|
||||||
|
|
||||||
|
void setRPTCall1(const unsigned char* call1);
|
||||||
|
void setRPTCall2(const unsigned char* call2);
|
||||||
|
|
||||||
|
void getYourCall(unsigned char* call) const;
|
||||||
|
void setYourCall(const unsigned char* call);
|
||||||
|
|
||||||
|
void get(unsigned char* header) const;
|
||||||
|
|
||||||
|
CDStarHeader& operator=(const CDStarHeader& header);
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned char* m_header;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
336
DStarNetwork.cpp
Normal file
|
@ -0,0 +1,336 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2014,2016,2019 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 "DStarNetwork.h"
|
||||||
|
#include "StopWatch.h"
|
||||||
|
#include "Defines.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
const unsigned int BUFFER_LENGTH = 100U;
|
||||||
|
|
||||||
|
CDStarNetwork::CDStarNetwork(const std::string& gatewayAddress, unsigned int gatewayPort, unsigned int localPort, bool duplex, const char* version, bool debug) :
|
||||||
|
m_socket(localPort),
|
||||||
|
m_address(),
|
||||||
|
m_port(gatewayPort),
|
||||||
|
m_duplex(duplex),
|
||||||
|
m_version(version),
|
||||||
|
m_debug(debug),
|
||||||
|
m_enabled(false),
|
||||||
|
m_outId(0U),
|
||||||
|
m_outSeq(0U),
|
||||||
|
m_inId(0U),
|
||||||
|
m_buffer(1000U, "D-Star Network"),
|
||||||
|
m_pollTimer(1000U, 60U),
|
||||||
|
m_linkStatus(LS_NONE),
|
||||||
|
m_linkReflector(NULL)
|
||||||
|
{
|
||||||
|
m_address = CUDPSocket::lookup(gatewayAddress);
|
||||||
|
|
||||||
|
m_linkReflector = new unsigned char[DSTAR_LONG_CALLSIGN_LENGTH];
|
||||||
|
|
||||||
|
CStopWatch stopWatch;
|
||||||
|
::srand(stopWatch.start());
|
||||||
|
}
|
||||||
|
|
||||||
|
CDStarNetwork::~CDStarNetwork()
|
||||||
|
{
|
||||||
|
delete[] m_linkReflector;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDStarNetwork::open()
|
||||||
|
{
|
||||||
|
LogMessage("Opening D-Star network connection");
|
||||||
|
|
||||||
|
if (m_address.s_addr == INADDR_NONE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_pollTimer.start();
|
||||||
|
|
||||||
|
return m_socket.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDStarNetwork::writeHeader(const unsigned char* header, unsigned int length, bool busy)
|
||||||
|
{
|
||||||
|
assert(header != NULL);
|
||||||
|
|
||||||
|
unsigned char buffer[50U];
|
||||||
|
|
||||||
|
buffer[0] = 'D';
|
||||||
|
buffer[1] = 'S';
|
||||||
|
buffer[2] = 'R';
|
||||||
|
buffer[3] = 'P';
|
||||||
|
|
||||||
|
buffer[4] = busy ? 0x22U : 0x20U;
|
||||||
|
|
||||||
|
// Create a random id for this transmission
|
||||||
|
m_outId = (::rand() % 65535U) + 1U;
|
||||||
|
|
||||||
|
buffer[5] = m_outId / 256U; // Unique session id
|
||||||
|
buffer[6] = m_outId % 256U;
|
||||||
|
|
||||||
|
buffer[7] = 0U;
|
||||||
|
|
||||||
|
::memcpy(buffer + 8U, header, length);
|
||||||
|
|
||||||
|
m_outSeq = 0U;
|
||||||
|
|
||||||
|
if (m_debug)
|
||||||
|
CUtils::dump(1U, "D-Star Network Header Sent", buffer, 49U);
|
||||||
|
|
||||||
|
for (unsigned int i = 0U; i < 2U; i++) {
|
||||||
|
bool ret = m_socket.write(buffer, 49U, m_address, m_port);
|
||||||
|
if (!ret)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDStarNetwork::writeData(const unsigned char* data, unsigned int length, unsigned int errors, bool end, bool busy)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
unsigned char buffer[30U];
|
||||||
|
|
||||||
|
buffer[0] = 'D';
|
||||||
|
buffer[1] = 'S';
|
||||||
|
buffer[2] = 'R';
|
||||||
|
buffer[3] = 'P';
|
||||||
|
|
||||||
|
buffer[4] = busy ? 0x23U : 0x21U;
|
||||||
|
|
||||||
|
buffer[5] = m_outId / 256U; // Unique session id
|
||||||
|
buffer[6] = m_outId % 256U;
|
||||||
|
|
||||||
|
// If this is a data sync, reset the sequence to zero
|
||||||
|
if (data[9] == 0x55 && data[10] == 0x2D && data[11] == 0x16)
|
||||||
|
m_outSeq = 0U;
|
||||||
|
|
||||||
|
buffer[7] = m_outSeq;
|
||||||
|
if (end)
|
||||||
|
buffer[7] |= 0x40U; // End of data marker
|
||||||
|
|
||||||
|
buffer[8] = errors;
|
||||||
|
|
||||||
|
m_outSeq++;
|
||||||
|
if (m_outSeq > 0x14U)
|
||||||
|
m_outSeq = 0U;
|
||||||
|
|
||||||
|
::memcpy(buffer + 9U, data, length);
|
||||||
|
|
||||||
|
if (m_debug)
|
||||||
|
CUtils::dump(1U, "D-Star Network Data Sent", buffer, length + 9U);
|
||||||
|
|
||||||
|
return m_socket.write(buffer, length + 9U, m_address, m_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDStarNetwork::writePoll(const char* text)
|
||||||
|
{
|
||||||
|
assert(text != NULL);
|
||||||
|
|
||||||
|
unsigned char buffer[40U];
|
||||||
|
|
||||||
|
buffer[0] = 'D';
|
||||||
|
buffer[1] = 'S';
|
||||||
|
buffer[2] = 'R';
|
||||||
|
buffer[3] = 'P';
|
||||||
|
|
||||||
|
buffer[4] = 0x0A; // Poll with text
|
||||||
|
|
||||||
|
unsigned int length = ::strlen(text);
|
||||||
|
|
||||||
|
// Include the nul at the end also
|
||||||
|
::memcpy(buffer + 5U, text, length + 1U);
|
||||||
|
|
||||||
|
// if (m_debug)
|
||||||
|
// CUtils::dump(1U, "D-Star Network Poll Sent", buffer, 6U + length);
|
||||||
|
|
||||||
|
return m_socket.write(buffer, 6U + length, m_address, m_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDStarNetwork::clock(unsigned int ms)
|
||||||
|
{
|
||||||
|
m_pollTimer.clock(ms);
|
||||||
|
if (m_pollTimer.hasExpired()) {
|
||||||
|
char text[60U];
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
if (m_duplex)
|
||||||
|
::sprintf(text, "win_mmdvm-%s", m_version);
|
||||||
|
else
|
||||||
|
::sprintf(text, "win_mmdvm-dvmega-%s", m_version);
|
||||||
|
#else
|
||||||
|
if (m_duplex)
|
||||||
|
::sprintf(text, "linux_mmdvm-%s", m_version);
|
||||||
|
else
|
||||||
|
::sprintf(text, "linux_mmdvm-dvmega-%s", m_version);
|
||||||
|
#endif
|
||||||
|
writePoll(text);
|
||||||
|
m_pollTimer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char buffer[BUFFER_LENGTH];
|
||||||
|
|
||||||
|
in_addr address;
|
||||||
|
unsigned int port;
|
||||||
|
int length = m_socket.read(buffer, BUFFER_LENGTH, address, port);
|
||||||
|
if (length <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Check if the data is for us
|
||||||
|
if (m_address.s_addr != address.s_addr || m_port != port) {
|
||||||
|
LogMessage("D-Star packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, m_port, port);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalid packet type?
|
||||||
|
if (::memcmp(buffer, "DSRP", 4U) != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (buffer[4]) {
|
||||||
|
case 0x00U: // NETWORK_TEXT;
|
||||||
|
if (m_debug)
|
||||||
|
CUtils::dump(1U, "D-Star Network Status Received", buffer, length);
|
||||||
|
|
||||||
|
m_linkStatus = LINK_STATUS(buffer[25U]);
|
||||||
|
::memcpy(m_linkReflector, buffer + 26U, DSTAR_LONG_CALLSIGN_LENGTH);
|
||||||
|
LogMessage("D-Star link status set to \"%20.20s\"", buffer + 5U);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case 0x01U: // NETWORK_TEMPTEXT;
|
||||||
|
case 0x04U: // NETWORK_STATUS1..5
|
||||||
|
case 0x24U: // NETWORK_DD_DATA
|
||||||
|
return;
|
||||||
|
|
||||||
|
case 0x20U: // NETWORK_HEADER
|
||||||
|
if (m_inId == 0U && m_enabled) {
|
||||||
|
if (m_debug)
|
||||||
|
CUtils::dump(1U, "D-Star Network Header Received", buffer, length);
|
||||||
|
|
||||||
|
m_inId = buffer[5] * 256U + buffer[6];
|
||||||
|
|
||||||
|
unsigned char c = length - 7U;
|
||||||
|
m_buffer.addData(&c, 1U);
|
||||||
|
|
||||||
|
c = TAG_HEADER;
|
||||||
|
m_buffer.addData(&c, 1U);
|
||||||
|
|
||||||
|
m_buffer.addData(buffer + 8U, length - 8U);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x21U: // NETWORK_DATA
|
||||||
|
if (m_enabled) {
|
||||||
|
if (m_debug)
|
||||||
|
CUtils::dump(1U, "D-Star Network Data Received", buffer, length);
|
||||||
|
|
||||||
|
uint16_t id = buffer[5] * 256U + buffer[6];
|
||||||
|
|
||||||
|
// Check that the stream id matches the valid header, reject otherwise
|
||||||
|
if (id == m_inId && m_enabled) {
|
||||||
|
unsigned char ctrl[3U];
|
||||||
|
|
||||||
|
ctrl[0U] = length - 7U;
|
||||||
|
|
||||||
|
// Is this the last packet in the stream?
|
||||||
|
if ((buffer[7] & 0x40) == 0x40) {
|
||||||
|
m_inId = 0U;
|
||||||
|
ctrl[1U] = TAG_EOT;
|
||||||
|
} else {
|
||||||
|
ctrl[1U] = TAG_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrl[2U] = buffer[7] & 0x3FU;
|
||||||
|
|
||||||
|
m_buffer.addData(ctrl, 3U);
|
||||||
|
|
||||||
|
m_buffer.addData(buffer + 9U, length - 9U);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
CUtils::dump("Unknown D-Star packet from the Gateway", buffer, length);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CDStarNetwork::read(unsigned char* data, unsigned int length)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
if (m_buffer.isEmpty())
|
||||||
|
return 0U;
|
||||||
|
|
||||||
|
unsigned char c = 0U;
|
||||||
|
m_buffer.getData(&c, 1U);
|
||||||
|
|
||||||
|
assert(c <= 100U);
|
||||||
|
assert(c <= length);
|
||||||
|
|
||||||
|
unsigned char buffer[100U];
|
||||||
|
m_buffer.getData(buffer, c);
|
||||||
|
|
||||||
|
switch (buffer[0U]) {
|
||||||
|
case TAG_HEADER:
|
||||||
|
case TAG_DATA:
|
||||||
|
case TAG_EOT:
|
||||||
|
::memcpy(data, buffer, c);
|
||||||
|
return c;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDStarNetwork::reset()
|
||||||
|
{
|
||||||
|
m_inId = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDStarNetwork::close()
|
||||||
|
{
|
||||||
|
m_socket.close();
|
||||||
|
|
||||||
|
LogMessage("Closing D-Star network connection");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDStarNetwork::enable(bool enabled)
|
||||||
|
{
|
||||||
|
if (enabled && !m_enabled)
|
||||||
|
reset();
|
||||||
|
else if (!enabled && m_enabled)
|
||||||
|
m_buffer.clear();
|
||||||
|
|
||||||
|
m_enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDStarNetwork::getStatus(LINK_STATUS& status, unsigned char* reflector)
|
||||||
|
{
|
||||||
|
assert(reflector != NULL);
|
||||||
|
|
||||||
|
status = m_linkStatus;
|
||||||
|
|
||||||
|
::memcpy(reflector, m_linkReflector, DSTAR_LONG_CALLSIGN_LENGTH);
|
||||||
|
}
|
71
DStarNetwork.h
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2014,2016 by Jonathan Naylor G4KLX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DStarNetwork_H
|
||||||
|
#define DStarNetwork_H
|
||||||
|
|
||||||
|
#include "DStarDefines.h"
|
||||||
|
#include "RingBuffer.h"
|
||||||
|
#include "UDPSocket.h"
|
||||||
|
#include "Timer.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class CDStarNetwork {
|
||||||
|
public:
|
||||||
|
CDStarNetwork(const std::string& gatewayAddress, unsigned int gatewayPort, unsigned int localPort, bool duplex, const char* version, bool debug);
|
||||||
|
~CDStarNetwork();
|
||||||
|
|
||||||
|
bool open();
|
||||||
|
|
||||||
|
void enable(bool enabled);
|
||||||
|
|
||||||
|
bool writeHeader(const unsigned char* header, unsigned int length, bool busy);
|
||||||
|
bool writeData(const unsigned char* data, unsigned int length, unsigned int errors, bool end, bool busy);
|
||||||
|
|
||||||
|
void getStatus(LINK_STATUS& status, unsigned char* reflector);
|
||||||
|
|
||||||
|
unsigned int read(unsigned char* data, unsigned int length);
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
void close();
|
||||||
|
|
||||||
|
void clock(unsigned int ms);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CUDPSocket m_socket;
|
||||||
|
in_addr m_address;
|
||||||
|
unsigned int m_port;
|
||||||
|
bool m_duplex;
|
||||||
|
const char* m_version;
|
||||||
|
bool m_debug;
|
||||||
|
bool m_enabled;
|
||||||
|
uint16_t m_outId;
|
||||||
|
uint8_t m_outSeq;
|
||||||
|
uint16_t m_inId;
|
||||||
|
CRingBuffer<unsigned char> m_buffer;
|
||||||
|
CTimer m_pollTimer;
|
||||||
|
LINK_STATUS m_linkStatus;
|
||||||
|
unsigned char* m_linkReflector;
|
||||||
|
|
||||||
|
bool writePoll(const char* text);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
158
DStarSlowData.cpp
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
/*
|
||||||
|
* 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 "DStarSlowData.h"
|
||||||
|
#include "DStarDefines.h"
|
||||||
|
#include "CRC.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
CDStarSlowData::CDStarSlowData() :
|
||||||
|
m_header(NULL),
|
||||||
|
m_ptr(0U),
|
||||||
|
m_buffer(NULL),
|
||||||
|
m_text(NULL),
|
||||||
|
m_textPtr(0U),
|
||||||
|
m_state(SDD_FIRST)
|
||||||
|
{
|
||||||
|
m_header = new unsigned char[50U]; // DSTAR_HEADER_LENGTH_BYTES
|
||||||
|
m_buffer = new unsigned char[DSTAR_DATA_FRAME_LENGTH_BYTES * 2U];
|
||||||
|
m_text = new unsigned char[24U];
|
||||||
|
}
|
||||||
|
|
||||||
|
CDStarSlowData::~CDStarSlowData()
|
||||||
|
{
|
||||||
|
delete[] m_header;
|
||||||
|
delete[] m_buffer;
|
||||||
|
delete[] m_text;
|
||||||
|
}
|
||||||
|
|
||||||
|
CDStarHeader* CDStarSlowData::add(const unsigned char* data)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
switch (m_state) {
|
||||||
|
case SDD_FIRST:
|
||||||
|
m_buffer[0U] = data[9U] ^ DSTAR_SCRAMBLER_BYTES[0U];
|
||||||
|
m_buffer[1U] = data[10U] ^ DSTAR_SCRAMBLER_BYTES[1U];
|
||||||
|
m_buffer[2U] = data[11U] ^ DSTAR_SCRAMBLER_BYTES[2U];
|
||||||
|
m_state = SDD_SECOND;
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
case SDD_SECOND:
|
||||||
|
m_buffer[3U] = data[9U] ^ DSTAR_SCRAMBLER_BYTES[0U];
|
||||||
|
m_buffer[4U] = data[10U] ^ DSTAR_SCRAMBLER_BYTES[1U];
|
||||||
|
m_buffer[5U] = data[11U] ^ DSTAR_SCRAMBLER_BYTES[2U];
|
||||||
|
m_state = SDD_FIRST;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((m_buffer[0U] & DSTAR_SLOW_DATA_TYPE_MASK) != DSTAR_SLOW_DATA_TYPE_HEADER)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (m_ptr >= 45U)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
::memcpy(m_header + m_ptr, m_buffer + 1U, 5U);
|
||||||
|
m_ptr += 5U;
|
||||||
|
|
||||||
|
// Clean up the data
|
||||||
|
m_header[0U] &= (DSTAR_INTERRUPTED_MASK | DSTAR_URGENT_MASK | DSTAR_REPEATER_MASK);
|
||||||
|
m_header[1U] = 0x00U;
|
||||||
|
m_header[2U] = 0x00U;
|
||||||
|
|
||||||
|
for (unsigned int i = 3U; i < 39U; i++)
|
||||||
|
m_header[i] &= 0x7FU;
|
||||||
|
|
||||||
|
// Check the CRC
|
||||||
|
bool ret = CCRC::checkCCITT161(m_header, DSTAR_HEADER_LENGTH_BYTES);
|
||||||
|
if (!ret) {
|
||||||
|
if (m_ptr == 45U)
|
||||||
|
LogMessage("D-Star, invalid slow data header");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CDStarHeader(m_header);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDStarSlowData::start()
|
||||||
|
{
|
||||||
|
::memset(m_header, 0x00U, DSTAR_HEADER_LENGTH_BYTES);
|
||||||
|
|
||||||
|
m_ptr = 0U;
|
||||||
|
m_state = SDD_FIRST;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDStarSlowData::reset()
|
||||||
|
{
|
||||||
|
m_ptr = 0U;
|
||||||
|
m_state = SDD_FIRST;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDStarSlowData::setText(const char* text)
|
||||||
|
{
|
||||||
|
assert(text != NULL);
|
||||||
|
|
||||||
|
m_text[0U] = DSTAR_SLOW_DATA_TYPE_TEXT | 0U;
|
||||||
|
m_text[1U] = text[0U];
|
||||||
|
m_text[2U] = text[1U];
|
||||||
|
m_text[3U] = text[2U];
|
||||||
|
m_text[4U] = text[3U];
|
||||||
|
m_text[5U] = text[4U];
|
||||||
|
|
||||||
|
m_text[6U] = DSTAR_SLOW_DATA_TYPE_TEXT | 1U;
|
||||||
|
m_text[7U] = text[5U];
|
||||||
|
m_text[8U] = text[6U];
|
||||||
|
m_text[9U] = text[7U];
|
||||||
|
m_text[10U] = text[8U];
|
||||||
|
m_text[11U] = text[9U];
|
||||||
|
|
||||||
|
m_text[12U] = DSTAR_SLOW_DATA_TYPE_TEXT | 2U;
|
||||||
|
m_text[13U] = text[10U];
|
||||||
|
m_text[14U] = text[11U];
|
||||||
|
m_text[15U] = text[12U];
|
||||||
|
m_text[16U] = text[13U];
|
||||||
|
m_text[17U] = text[14U];
|
||||||
|
|
||||||
|
m_text[18U] = DSTAR_SLOW_DATA_TYPE_TEXT | 3U;
|
||||||
|
m_text[19U] = text[15U];
|
||||||
|
m_text[20U] = text[16U];
|
||||||
|
m_text[21U] = text[17U];
|
||||||
|
m_text[22U] = text[18U];
|
||||||
|
m_text[23U] = text[19U];
|
||||||
|
|
||||||
|
m_textPtr = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDStarSlowData::get(unsigned char* data)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
if (m_textPtr < 24U) {
|
||||||
|
data[0U] = m_text[m_textPtr++] ^ DSTAR_SCRAMBLER_BYTES[0U];
|
||||||
|
data[1U] = m_text[m_textPtr++] ^ DSTAR_SCRAMBLER_BYTES[1U];
|
||||||
|
data[2U] = m_text[m_textPtr++] ^ DSTAR_SCRAMBLER_BYTES[2U];
|
||||||
|
} else {
|
||||||
|
data[0U] = 'f' ^ DSTAR_SCRAMBLER_BYTES[0U];
|
||||||
|
data[1U] = 'f' ^ DSTAR_SCRAMBLER_BYTES[1U];
|
||||||
|
data[2U] = 'f' ^ DSTAR_SCRAMBLER_BYTES[2U];
|
||||||
|
}
|
||||||
|
}
|
52
DStarSlowData.h
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DStarSlowData_H
|
||||||
|
#define DStarSlowData_H
|
||||||
|
|
||||||
|
#include "DStarHeader.h"
|
||||||
|
|
||||||
|
class CDStarSlowData {
|
||||||
|
public:
|
||||||
|
CDStarSlowData();
|
||||||
|
~CDStarSlowData();
|
||||||
|
|
||||||
|
CDStarHeader* add(const unsigned char* data);
|
||||||
|
|
||||||
|
void start();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
void setText(const char* text);
|
||||||
|
void get(unsigned char* data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned char* m_header;
|
||||||
|
unsigned int m_ptr;
|
||||||
|
unsigned char* m_buffer;
|
||||||
|
unsigned char* m_text;
|
||||||
|
unsigned int m_textPtr;
|
||||||
|
|
||||||
|
enum SDD_STATE {
|
||||||
|
SDD_FIRST,
|
||||||
|
SDD_SECOND
|
||||||
|
};
|
||||||
|
|
||||||
|
SDD_STATE m_state;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
59
Defines.h
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -23,19 +23,62 @@ const unsigned char MODE_IDLE = 0U;
|
||||||
const unsigned char MODE_DSTAR = 1U;
|
const unsigned char MODE_DSTAR = 1U;
|
||||||
const unsigned char MODE_DMR = 2U;
|
const unsigned char MODE_DMR = 2U;
|
||||||
const unsigned char MODE_YSF = 3U;
|
const unsigned char MODE_YSF = 3U;
|
||||||
|
const unsigned char MODE_P25 = 4U;
|
||||||
|
const unsigned char MODE_NXDN = 5U;
|
||||||
|
const unsigned char MODE_POCSAG = 6U;
|
||||||
|
|
||||||
|
const unsigned char MODE_FM = 10U;
|
||||||
|
|
||||||
|
const unsigned char MODE_CW = 98U;
|
||||||
|
const unsigned char MODE_LOCKOUT = 99U;
|
||||||
|
const unsigned char MODE_ERROR = 100U;
|
||||||
|
const unsigned char MODE_QUIT = 110U;
|
||||||
|
|
||||||
const unsigned char TAG_HEADER = 0x00U;
|
const unsigned char TAG_HEADER = 0x00U;
|
||||||
const unsigned char TAG_DATA = 0x01U;
|
const unsigned char TAG_DATA = 0x01U;
|
||||||
const unsigned char TAG_LOST = 0x02U;
|
const unsigned char TAG_LOST = 0x02U;
|
||||||
const unsigned char TAG_EOT = 0x03U;
|
const unsigned char TAG_EOT = 0x03U;
|
||||||
|
|
||||||
enum RPT_STATE {
|
enum HW_TYPE {
|
||||||
RS_LISTENING,
|
HWT_MMDVM,
|
||||||
RS_LATE_ENTRY,
|
HWT_DVMEGA,
|
||||||
RS_RELAYING_RF_AUDIO,
|
HWT_MMDVM_ZUMSPOT,
|
||||||
RS_RELAYING_NETWORK_AUDIO,
|
HWT_MMDVM_HS_HAT,
|
||||||
RS_RELAYING_RF_DATA,
|
HWT_MMDVM_HS_DUAL_HAT,
|
||||||
RS_RELAYING_NETWORK_DATA
|
HWT_NANO_HOTSPOT,
|
||||||
|
HWT_NANO_DV,
|
||||||
|
HWT_D2RG_MMDVM_HS,
|
||||||
|
HWT_MMDVM_HS,
|
||||||
|
HWT_OPENGD77_HS,
|
||||||
|
HWT_UNKNOWN
|
||||||
|
};
|
||||||
|
|
||||||
|
enum RPT_RF_STATE {
|
||||||
|
RS_RF_LISTENING,
|
||||||
|
RS_RF_LATE_ENTRY,
|
||||||
|
RS_RF_AUDIO,
|
||||||
|
RS_RF_DATA,
|
||||||
|
RS_RF_REJECTED,
|
||||||
|
RS_RF_INVALID
|
||||||
|
};
|
||||||
|
|
||||||
|
enum RPT_NET_STATE {
|
||||||
|
RS_NET_IDLE,
|
||||||
|
RS_NET_AUDIO,
|
||||||
|
RS_NET_DATA
|
||||||
|
};
|
||||||
|
|
||||||
|
enum DMR_BEACONS {
|
||||||
|
DMR_BEACONS_OFF,
|
||||||
|
DMR_BEACONS_NETWORK,
|
||||||
|
DMR_BEACONS_TIMED
|
||||||
|
};
|
||||||
|
|
||||||
|
enum DMR_OVCM_TYPES {
|
||||||
|
DMR_OVCM_OFF,
|
||||||
|
DMR_OVCM_RX_ON,
|
||||||
|
DMR_OVCM_TX_ON,
|
||||||
|
DMR_OVCM_ON
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
642
Display.cpp
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2016 by Jonathan Naylor G4KLX
|
* Copyright (C) 2016,2017,2018,2020 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -17,7 +17,645 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Display.h"
|
#include "Display.h"
|
||||||
|
#include "Defines.h"
|
||||||
|
#include "SerialController.h"
|
||||||
|
#include "ModemSerialPort.h"
|
||||||
|
#include "NullDisplay.h"
|
||||||
|
#include "TFTSerial.h"
|
||||||
|
#include "TFTSurenoo.h"
|
||||||
|
#include "LCDproc.h"
|
||||||
|
#include "Nextion.h"
|
||||||
|
#include "CASTInfo.h"
|
||||||
|
#include "Conf.h"
|
||||||
|
#include "Modem.h"
|
||||||
|
#include "UMP.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
IDisplay::~IDisplay()
|
#if defined(HD44780)
|
||||||
|
#include "HD44780.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(OLED)
|
||||||
|
#include "OLED.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
CDisplay::CDisplay() :
|
||||||
|
m_timer1(3000U, 3U),
|
||||||
|
m_timer2(3000U, 3U),
|
||||||
|
m_mode1(MODE_IDLE),
|
||||||
|
m_mode2(MODE_IDLE)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CDisplay::~CDisplay()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::setIdle()
|
||||||
|
{
|
||||||
|
m_timer1.stop();
|
||||||
|
m_timer2.stop();
|
||||||
|
|
||||||
|
m_mode1 = MODE_IDLE;
|
||||||
|
m_mode2 = MODE_IDLE;
|
||||||
|
|
||||||
|
setIdleInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::setLockout()
|
||||||
|
{
|
||||||
|
m_timer1.stop();
|
||||||
|
m_timer2.stop();
|
||||||
|
|
||||||
|
m_mode1 = MODE_IDLE;
|
||||||
|
m_mode2 = MODE_IDLE;
|
||||||
|
|
||||||
|
setLockoutInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::setError(const char* text)
|
||||||
|
{
|
||||||
|
assert(text != NULL);
|
||||||
|
|
||||||
|
m_timer1.stop();
|
||||||
|
m_timer2.stop();
|
||||||
|
|
||||||
|
m_mode1 = MODE_IDLE;
|
||||||
|
m_mode2 = MODE_IDLE;
|
||||||
|
|
||||||
|
setErrorInt(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::setQuit()
|
||||||
|
{
|
||||||
|
m_timer1.stop();
|
||||||
|
m_timer2.stop();
|
||||||
|
|
||||||
|
m_mode1 = MODE_QUIT;
|
||||||
|
m_mode2 = MODE_QUIT;
|
||||||
|
|
||||||
|
setQuitInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::setFM()
|
||||||
|
{
|
||||||
|
m_timer1.stop();
|
||||||
|
m_timer2.stop();
|
||||||
|
|
||||||
|
m_mode1 = MODE_FM;
|
||||||
|
m_mode2 = MODE_FM;
|
||||||
|
|
||||||
|
setFMInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writeDStar(const char* my1, const char* my2, const char* your, const char* type, const char* reflector)
|
||||||
|
{
|
||||||
|
assert(my1 != NULL);
|
||||||
|
assert(my2 != NULL);
|
||||||
|
assert(your != NULL);
|
||||||
|
assert(type != NULL);
|
||||||
|
assert(reflector != NULL);
|
||||||
|
|
||||||
|
m_timer1.start();
|
||||||
|
m_mode1 = MODE_IDLE;
|
||||||
|
|
||||||
|
writeDStarInt(my1, my2, your, type, reflector);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writeDStarRSSI(unsigned char rssi)
|
||||||
|
{
|
||||||
|
if (rssi != 0U)
|
||||||
|
writeDStarRSSIInt(rssi);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writeDStarBER(float ber)
|
||||||
|
{
|
||||||
|
writeDStarBERInt(ber);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::clearDStar()
|
||||||
|
{
|
||||||
|
if (m_timer1.hasExpired()) {
|
||||||
|
clearDStarInt();
|
||||||
|
m_timer1.stop();
|
||||||
|
m_mode1 = MODE_IDLE;
|
||||||
|
} else {
|
||||||
|
m_mode1 = MODE_DSTAR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writeDMR(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type)
|
||||||
|
{
|
||||||
|
assert(type != NULL);
|
||||||
|
|
||||||
|
if (slotNo == 1U) {
|
||||||
|
m_timer1.start();
|
||||||
|
m_mode1 = MODE_IDLE;
|
||||||
|
} else {
|
||||||
|
m_timer2.start();
|
||||||
|
m_mode2 = MODE_IDLE;
|
||||||
|
}
|
||||||
|
writeDMRInt(slotNo, src, group, dst, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writeDMR(unsigned int slotNo, const class CUserDBentry& src, bool group, const std::string& dst, const char* type)
|
||||||
|
{
|
||||||
|
assert(type != NULL);
|
||||||
|
|
||||||
|
if (slotNo == 1U) {
|
||||||
|
m_timer1.start();
|
||||||
|
m_mode1 = MODE_IDLE;
|
||||||
|
} else {
|
||||||
|
m_timer2.start();
|
||||||
|
m_mode2 = MODE_IDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (int err = writeDMRIntEx(slotNo, src, group, dst, type)) {
|
||||||
|
std::string src_str = src.get(keyCALLSIGN);
|
||||||
|
if (err < 0 && !src.get(keyFIRST_NAME).empty()) {
|
||||||
|
// emulate the result of old CDMRLookup::findWithName()
|
||||||
|
// (it returned callsign and firstname)
|
||||||
|
src_str += " " + src.get(keyFIRST_NAME);
|
||||||
|
}
|
||||||
|
writeDMRInt(slotNo, src_str, group, dst, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writeDMRRSSI(unsigned int slotNo, unsigned char rssi)
|
||||||
|
{
|
||||||
|
if (rssi != 0U)
|
||||||
|
writeDMRRSSIInt(slotNo, rssi);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writeDMRTA(unsigned int slotNo, unsigned char* talkerAlias, const char* type)
|
||||||
|
{
|
||||||
|
if (strcmp(type," ")==0) { writeDMRTAInt(slotNo, (unsigned char*)"", type); return; }
|
||||||
|
if (strlen((char*)talkerAlias)>=4U) writeDMRTAInt(slotNo, (unsigned char*)talkerAlias, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writeDMRBER(unsigned int slotNo, float ber)
|
||||||
|
{
|
||||||
|
writeDMRBERInt(slotNo, ber);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::clearDMR(unsigned int slotNo)
|
||||||
|
{
|
||||||
|
if (slotNo == 1U) {
|
||||||
|
if (m_timer1.hasExpired()) {
|
||||||
|
clearDMRInt(slotNo);
|
||||||
|
m_timer1.stop();
|
||||||
|
m_mode1 = MODE_IDLE;
|
||||||
|
} else {
|
||||||
|
m_mode1 = MODE_DMR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (m_timer2.hasExpired()) {
|
||||||
|
clearDMRInt(slotNo);
|
||||||
|
m_timer2.stop();
|
||||||
|
m_mode2 = MODE_IDLE;
|
||||||
|
} else {
|
||||||
|
m_mode2 = MODE_DMR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writeFusion(const char* source, const char* dest, const char* type, const char* origin)
|
||||||
|
{
|
||||||
|
assert(source != NULL);
|
||||||
|
assert(dest != NULL);
|
||||||
|
assert(type != NULL);
|
||||||
|
assert(origin != NULL);
|
||||||
|
|
||||||
|
m_timer1.start();
|
||||||
|
m_mode1 = MODE_IDLE;
|
||||||
|
|
||||||
|
writeFusionInt(source, dest, type, origin);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writeFusionRSSI(unsigned char rssi)
|
||||||
|
{
|
||||||
|
if (rssi != 0U)
|
||||||
|
writeFusionRSSIInt(rssi);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writeFusionBER(float ber)
|
||||||
|
{
|
||||||
|
writeFusionBERInt(ber);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::clearFusion()
|
||||||
|
{
|
||||||
|
if (m_timer1.hasExpired()) {
|
||||||
|
clearFusionInt();
|
||||||
|
m_timer1.stop();
|
||||||
|
m_mode1 = MODE_IDLE;
|
||||||
|
} else {
|
||||||
|
m_mode1 = MODE_YSF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writeP25(const char* source, bool group, unsigned int dest, const char* type)
|
||||||
|
{
|
||||||
|
assert(source != NULL);
|
||||||
|
assert(type != NULL);
|
||||||
|
|
||||||
|
m_timer1.start();
|
||||||
|
m_mode1 = MODE_IDLE;
|
||||||
|
|
||||||
|
writeP25Int(source, group, dest, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writeP25RSSI(unsigned char rssi)
|
||||||
|
{
|
||||||
|
if (rssi != 0U)
|
||||||
|
writeP25RSSIInt(rssi);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writeP25BER(float ber)
|
||||||
|
{
|
||||||
|
writeP25BERInt(ber);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::clearP25()
|
||||||
|
{
|
||||||
|
if (m_timer1.hasExpired()) {
|
||||||
|
clearP25Int();
|
||||||
|
m_timer1.stop();
|
||||||
|
m_mode1 = MODE_IDLE;
|
||||||
|
} else {
|
||||||
|
m_mode1 = MODE_P25;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writeNXDN(const char* source, bool group, unsigned int dest, const char* type)
|
||||||
|
{
|
||||||
|
assert(source != NULL);
|
||||||
|
assert(type != NULL);
|
||||||
|
|
||||||
|
m_timer1.start();
|
||||||
|
m_mode1 = MODE_IDLE;
|
||||||
|
|
||||||
|
writeNXDNInt(source, group, dest, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writeNXDN(const class CUserDBentry& source, bool group, unsigned int dest, const char* type)
|
||||||
|
{
|
||||||
|
assert(type != NULL);
|
||||||
|
|
||||||
|
m_timer1.start();
|
||||||
|
m_mode1 = MODE_IDLE;
|
||||||
|
|
||||||
|
if (writeNXDNIntEx(source, group, dest, type))
|
||||||
|
writeNXDNInt(source.get(keyCALLSIGN).c_str(), group, dest, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writeNXDNRSSI(unsigned char rssi)
|
||||||
|
{
|
||||||
|
if (rssi != 0U)
|
||||||
|
writeNXDNRSSIInt(rssi);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writeNXDNBER(float ber)
|
||||||
|
{
|
||||||
|
writeNXDNBERInt(ber);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::clearNXDN()
|
||||||
|
{
|
||||||
|
if (m_timer1.hasExpired()) {
|
||||||
|
clearNXDNInt();
|
||||||
|
m_timer1.stop();
|
||||||
|
m_mode1 = MODE_IDLE;
|
||||||
|
} else {
|
||||||
|
m_mode1 = MODE_NXDN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writePOCSAG(uint32_t ric, const std::string& message)
|
||||||
|
{
|
||||||
|
m_timer1.start();
|
||||||
|
m_mode1 = MODE_POCSAG;
|
||||||
|
|
||||||
|
writePOCSAGInt(ric, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::clearPOCSAG()
|
||||||
|
{
|
||||||
|
if (m_timer1.hasExpired()) {
|
||||||
|
clearPOCSAGInt();
|
||||||
|
m_timer1.stop();
|
||||||
|
m_mode1 = MODE_IDLE;
|
||||||
|
} else {
|
||||||
|
m_mode1 = MODE_POCSAG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writeCW()
|
||||||
|
{
|
||||||
|
m_timer1.start();
|
||||||
|
m_mode1 = MODE_CW;
|
||||||
|
|
||||||
|
writeCWInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::clock(unsigned int ms)
|
||||||
|
{
|
||||||
|
m_timer1.clock(ms);
|
||||||
|
if (m_timer1.isRunning() && m_timer1.hasExpired()) {
|
||||||
|
switch (m_mode1) {
|
||||||
|
case MODE_DSTAR:
|
||||||
|
clearDStarInt();
|
||||||
|
m_mode1 = MODE_IDLE;
|
||||||
|
m_timer1.stop();
|
||||||
|
break;
|
||||||
|
case MODE_DMR:
|
||||||
|
clearDMRInt(1U);
|
||||||
|
m_mode1 = MODE_IDLE;
|
||||||
|
m_timer1.stop();
|
||||||
|
break;
|
||||||
|
case MODE_YSF:
|
||||||
|
clearFusionInt();
|
||||||
|
m_mode1 = MODE_IDLE;
|
||||||
|
m_timer1.stop();
|
||||||
|
break;
|
||||||
|
case MODE_P25:
|
||||||
|
clearP25Int();
|
||||||
|
m_mode1 = MODE_IDLE;
|
||||||
|
m_timer1.stop();
|
||||||
|
break;
|
||||||
|
case MODE_NXDN:
|
||||||
|
clearNXDNInt();
|
||||||
|
m_mode1 = MODE_IDLE;
|
||||||
|
m_timer1.stop();
|
||||||
|
break;
|
||||||
|
case MODE_POCSAG:
|
||||||
|
clearPOCSAGInt();
|
||||||
|
m_mode1 = MODE_IDLE;
|
||||||
|
m_timer1.stop();
|
||||||
|
break;
|
||||||
|
case MODE_CW:
|
||||||
|
clearCWInt();
|
||||||
|
m_mode1 = MODE_IDLE;
|
||||||
|
m_timer1.stop();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timer/mode 2 are only used for DMR
|
||||||
|
m_timer2.clock(ms);
|
||||||
|
if (m_timer2.isRunning() && m_timer2.hasExpired()) {
|
||||||
|
if (m_mode2 == MODE_DMR) {
|
||||||
|
clearDMRInt(2U);
|
||||||
|
m_mode2 = MODE_IDLE;
|
||||||
|
m_timer2.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clockInt(ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::clockInt(unsigned int ms)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writeDStarRSSIInt(unsigned char rssi)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writeDStarBERInt(float ber)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int CDisplay::writeDMRIntEx(unsigned int slotNo, const class CUserDBentry& src, bool group, const std::string& dst, const char* type)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* return value:
|
||||||
|
* < 0 error condition (i.e. not supported)
|
||||||
|
* -> call writeXXXXInt() to display
|
||||||
|
* = 0 no error, writeXXXXIntEx() displayed whole status
|
||||||
|
* = 1 no error, writeXXXXIntEx() displayed partial status
|
||||||
|
* -> call writeXXXXInt() to display remain part
|
||||||
|
* > 1 reserved for future use
|
||||||
|
*/
|
||||||
|
return -1; // not supported
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writeDMRTAInt(unsigned int slotNo, unsigned char* talkerAlias, const char* type)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writeDMRBERInt(unsigned int slotNo, float ber)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writeFusionRSSIInt(unsigned char rssi)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writeFusionBERInt(float ber)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writeP25RSSIInt(unsigned char rssi)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writeP25BERInt(float ber)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writeNXDNRSSIInt(unsigned char rssi)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDisplay::writeNXDNBERInt(float ber)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int CDisplay::writeNXDNIntEx(const class CUserDBentry& source, bool group, unsigned int dest, const char* type)
|
||||||
|
{
|
||||||
|
/* return value definition is same as writeDMRIntEx() */
|
||||||
|
return -1; // not supported
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Factory method extracted from MMDVMHost.cpp - BG5HHP */
|
||||||
|
CDisplay* CDisplay::createDisplay(const CConf& conf, CUMP* ump, CModem* modem)
|
||||||
|
{
|
||||||
|
CDisplay *display = NULL;
|
||||||
|
|
||||||
|
std::string type = conf.getDisplay();
|
||||||
|
unsigned int dmrid = conf.getDMRId();
|
||||||
|
|
||||||
|
LogInfo("Display Parameters");
|
||||||
|
LogInfo(" Type: %s", type.c_str());
|
||||||
|
|
||||||
|
if (type == "TFT Serial" || type == "TFT Surenoo") {
|
||||||
|
std::string port = conf.getTFTSerialPort();
|
||||||
|
unsigned int brightness = conf.getTFTSerialBrightness();
|
||||||
|
|
||||||
|
LogInfo(" Port: %s", port.c_str());
|
||||||
|
LogInfo(" Brightness: %u", brightness);
|
||||||
|
|
||||||
|
ISerialPort* serial = NULL;
|
||||||
|
if (port == "modem")
|
||||||
|
serial = new CModemSerialPort(modem);
|
||||||
|
else
|
||||||
|
serial = new CSerialController(port, (type == "TFT Serial") ? SERIAL_9600 : SERIAL_115200);
|
||||||
|
|
||||||
|
if (type == "TFT Surenoo")
|
||||||
|
display = new CTFTSurenoo(conf.getCallsign(), dmrid, serial, brightness, conf.getDuplex());
|
||||||
|
else
|
||||||
|
display = new CTFTSerial(conf.getCallsign(), dmrid, serial, brightness);
|
||||||
|
} else if (type == "Nextion") {
|
||||||
|
std::string port = conf.getNextionPort();
|
||||||
|
unsigned int brightness = conf.getNextionBrightness();
|
||||||
|
bool displayClock = conf.getNextionDisplayClock();
|
||||||
|
bool utc = conf.getNextionUTC();
|
||||||
|
unsigned int idleBrightness = conf.getNextionIdleBrightness();
|
||||||
|
unsigned int screenLayout = conf.getNextionScreenLayout();
|
||||||
|
unsigned int txFrequency = conf.getTXFrequency();
|
||||||
|
unsigned int rxFrequency = conf.getRXFrequency();
|
||||||
|
bool displayTempInF = conf.getNextionTempInFahrenheit();
|
||||||
|
|
||||||
|
LogInfo(" Port: %s", port.c_str());
|
||||||
|
LogInfo(" Brightness: %u", brightness);
|
||||||
|
LogInfo(" Clock Display: %s", displayClock ? "yes" : "no");
|
||||||
|
if (displayClock)
|
||||||
|
LogInfo(" Display UTC: %s", utc ? "yes" : "no");
|
||||||
|
LogInfo(" Idle Brightness: %u", idleBrightness);
|
||||||
|
LogInfo(" Temperature in Fahrenheit: %s ", displayTempInF ? "yes" : "no");
|
||||||
|
|
||||||
|
switch (screenLayout) {
|
||||||
|
case 0U:
|
||||||
|
LogInfo(" Screen Layout: G4KLX (Default)");
|
||||||
|
break;
|
||||||
|
case 2U:
|
||||||
|
LogInfo(" Screen Layout: ON7LDS");
|
||||||
|
break;
|
||||||
|
case 3U:
|
||||||
|
LogInfo(" Screen Layout: DIY by ON7LDS");
|
||||||
|
break;
|
||||||
|
case 4U:
|
||||||
|
LogInfo(" Screen Layout: DIY by ON7LDS (High speed)");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LogInfo(" Screen Layout: %u (Unknown)", screenLayout);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (port == "modem") {
|
||||||
|
ISerialPort* serial = new CModemSerialPort(modem);
|
||||||
|
display = new CNextion(conf.getCallsign(), dmrid, serial, brightness, displayClock, utc, idleBrightness, screenLayout, txFrequency, rxFrequency, displayTempInF, conf.getLocation());
|
||||||
|
} else if (port == "ump") {
|
||||||
|
if (ump != NULL) {
|
||||||
|
display = new CNextion(conf.getCallsign(), dmrid, ump, brightness, displayClock, utc, idleBrightness, screenLayout, txFrequency, rxFrequency, displayTempInF, conf.getLocation());
|
||||||
|
} else {
|
||||||
|
LogInfo(" NullDisplay loaded");
|
||||||
|
display = new CNullDisplay;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SERIAL_SPEED baudrate = SERIAL_9600;
|
||||||
|
if (screenLayout&0x0cU)
|
||||||
|
baudrate = SERIAL_115200;
|
||||||
|
|
||||||
|
LogInfo(" Display baudrate: %u ",baudrate);
|
||||||
|
ISerialPort* serial = new CSerialController(port, baudrate);
|
||||||
|
display = new CNextion(conf.getCallsign(), dmrid, serial, brightness, displayClock, utc, idleBrightness, screenLayout, txFrequency, rxFrequency, displayTempInF, conf.getLocation());
|
||||||
|
}
|
||||||
|
} else if (type == "LCDproc") {
|
||||||
|
std::string address = conf.getLCDprocAddress();
|
||||||
|
unsigned int port = conf.getLCDprocPort();
|
||||||
|
unsigned int localPort = conf.getLCDprocLocalPort();
|
||||||
|
bool displayClock = conf.getLCDprocDisplayClock();
|
||||||
|
bool utc = conf.getLCDprocUTC();
|
||||||
|
bool dimOnIdle = conf.getLCDprocDimOnIdle();
|
||||||
|
|
||||||
|
LogInfo(" Address: %s", address.c_str());
|
||||||
|
LogInfo(" Port: %u", port);
|
||||||
|
|
||||||
|
if (localPort == 0 )
|
||||||
|
LogInfo(" Local Port: random");
|
||||||
|
else
|
||||||
|
LogInfo(" Local Port: %u", localPort);
|
||||||
|
|
||||||
|
LogInfo(" Dim Display on Idle: %s", dimOnIdle ? "yes" : "no");
|
||||||
|
LogInfo(" Clock Display: %s", displayClock ? "yes" : "no");
|
||||||
|
|
||||||
|
if (displayClock)
|
||||||
|
LogInfo(" Display UTC: %s", utc ? "yes" : "no");
|
||||||
|
|
||||||
|
display = new CLCDproc(address.c_str(), port, localPort, conf.getCallsign(), dmrid, displayClock, utc, conf.getDuplex(), dimOnIdle);
|
||||||
|
#if defined(HD44780)
|
||||||
|
} else if (type == "HD44780") {
|
||||||
|
unsigned int rows = conf.getHD44780Rows();
|
||||||
|
unsigned int columns = conf.getHD44780Columns();
|
||||||
|
std::vector<unsigned int> pins = conf.getHD44780Pins();
|
||||||
|
unsigned int i2cAddress = conf.getHD44780i2cAddress();
|
||||||
|
bool pwm = conf.getHD44780PWM();
|
||||||
|
unsigned int pwmPin = conf.getHD44780PWMPin();
|
||||||
|
unsigned int pwmBright = conf.getHD44780PWMBright();
|
||||||
|
unsigned int pwmDim = conf.getHD44780PWMDim();
|
||||||
|
bool displayClock = conf.getHD44780DisplayClock();
|
||||||
|
bool utc = conf.getHD44780UTC();
|
||||||
|
|
||||||
|
if (pins.size() == 6U) {
|
||||||
|
LogInfo(" Rows: %u", rows);
|
||||||
|
LogInfo(" Columns: %u", columns);
|
||||||
|
|
||||||
|
#if defined(ADAFRUIT_DISPLAY) || defined(PCF8574_DISPLAY)
|
||||||
|
LogInfo(" Device Address: %#x", i2cAddress);
|
||||||
|
#else
|
||||||
|
LogInfo(" Pins: %u,%u,%u,%u,%u,%u", pins.at(0U), pins.at(1U), pins.at(2U), pins.at(3U), pins.at(4U), pins.at(5U));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
LogInfo(" PWM Backlight: %s", pwm ? "yes" : "no");
|
||||||
|
if (pwm) {
|
||||||
|
LogInfo(" PWM Pin: %u", pwmPin);
|
||||||
|
LogInfo(" PWM Bright: %u", pwmBright);
|
||||||
|
LogInfo(" PWM Dim: %u", pwmDim);
|
||||||
|
}
|
||||||
|
|
||||||
|
LogInfo(" Clock Display: %s", displayClock ? "yes" : "no");
|
||||||
|
if (displayClock)
|
||||||
|
LogInfo(" Display UTC: %s", utc ? "yes" : "no");
|
||||||
|
|
||||||
|
display = new CHD44780(rows, columns, conf.getCallsign(), dmrid, pins, i2cAddress, pwm, pwmPin, pwmBright, pwmDim, displayClock, utc, conf.getDuplex());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if defined(OLED)
|
||||||
|
} else if (type == "OLED") {
|
||||||
|
unsigned char type = conf.getOLEDType();
|
||||||
|
unsigned char brightness = conf.getOLEDBrightness();
|
||||||
|
bool invert = conf.getOLEDInvert();
|
||||||
|
bool scroll = conf.getOLEDScroll();
|
||||||
|
bool rotate = conf.getOLEDRotate();
|
||||||
|
bool logosaver = conf.getOLEDLogoScreensaver();
|
||||||
|
|
||||||
|
display = new COLED(type, brightness, invert, scroll, rotate, logosaver, conf.getDMRNetworkSlot1(), conf.getDMRNetworkSlot2());
|
||||||
|
#endif
|
||||||
|
} else if (type == "CAST") {
|
||||||
|
display = new CCASTInfo(modem);
|
||||||
|
} else {
|
||||||
|
LogWarning("No valid display found, disabling");
|
||||||
|
display = new CNullDisplay;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ret = display->open();
|
||||||
|
if (!ret) {
|
||||||
|
delete display;
|
||||||
|
display = new CNullDisplay;
|
||||||
|
}
|
||||||
|
|
||||||
|
return display;
|
||||||
|
}
|
||||||
|
|
112
Display.h
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2016 by Jonathan Naylor G4KLX
|
* Copyright (C) 2016,2017,2018,2020 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -19,32 +19,118 @@
|
||||||
#if !defined(DISPLAY_H)
|
#if !defined(DISPLAY_H)
|
||||||
#define DISPLAY_H
|
#define DISPLAY_H
|
||||||
|
|
||||||
|
#include "Timer.h"
|
||||||
|
#include "UserDBentry.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class IDisplay
|
#include <cstdint>
|
||||||
|
|
||||||
|
class CConf;
|
||||||
|
class CModem;
|
||||||
|
class CUMP;
|
||||||
|
|
||||||
|
class CDisplay
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~IDisplay() = 0;
|
CDisplay();
|
||||||
|
virtual ~CDisplay() = 0;
|
||||||
|
|
||||||
virtual bool open() = 0;
|
virtual bool open() = 0;
|
||||||
|
|
||||||
virtual void setIdle() = 0;
|
void setIdle();
|
||||||
|
void setLockout();
|
||||||
|
void setError(const char* text);
|
||||||
|
void setQuit();
|
||||||
|
void setFM();
|
||||||
|
|
||||||
virtual void setDStar() = 0;
|
void writeDStar(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
|
||||||
virtual void writeDStar(const std::string& call1, const std::string& call2) = 0;
|
void writeDStarRSSI(unsigned char rssi);
|
||||||
virtual void clearDStar() = 0;
|
void writeDStarBER(float ber);
|
||||||
|
void clearDStar();
|
||||||
|
|
||||||
virtual void setDMR() = 0;
|
void writeDMR(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type);
|
||||||
virtual void writeDMR(unsigned int slotNo, unsigned int srdId, bool group, unsigned int dstId) = 0;
|
void writeDMR(unsigned int slotNo, const class CUserDBentry& src, bool group, const std::string& dst, const char* type);
|
||||||
virtual void clearDMR(unsigned int slotNo) = 0;
|
void writeDMRRSSI(unsigned int slotNo, unsigned char rssi);
|
||||||
|
void writeDMRBER(unsigned int slotNo, float ber);
|
||||||
|
void writeDMRTA(unsigned int slotNo, unsigned char* talkerAlias, const char* type);
|
||||||
|
void clearDMR(unsigned int slotNo);
|
||||||
|
|
||||||
virtual void setFusion() = 0;
|
void writeFusion(const char* source, const char* dest, const char* type, const char* origin);
|
||||||
virtual void writeFusion(const std::string& callsign) = 0;
|
void writeFusionRSSI(unsigned char rssi);
|
||||||
virtual void clearFusion() = 0;
|
void writeFusionBER(float ber);
|
||||||
|
void clearFusion();
|
||||||
|
|
||||||
|
void writeP25(const char* source, bool group, unsigned int dest, const char* type);
|
||||||
|
void writeP25RSSI(unsigned char rssi);
|
||||||
|
void writeP25BER(float ber);
|
||||||
|
void clearP25();
|
||||||
|
|
||||||
|
void writeNXDN(const char* source, bool group, unsigned int dest, const char* type);
|
||||||
|
void writeNXDN(const class CUserDBentry& source, bool group, unsigned int dest, const char* type);
|
||||||
|
void writeNXDNRSSI(unsigned char rssi);
|
||||||
|
void writeNXDNBER(float ber);
|
||||||
|
void clearNXDN();
|
||||||
|
|
||||||
|
void writePOCSAG(uint32_t ric, const std::string& message);
|
||||||
|
void clearPOCSAG();
|
||||||
|
|
||||||
|
void writeCW();
|
||||||
|
|
||||||
virtual void close() = 0;
|
virtual void close() = 0;
|
||||||
|
|
||||||
|
void clock(unsigned int ms);
|
||||||
|
|
||||||
|
static CDisplay* createDisplay(const CConf& conf, CUMP* ump, CModem* modem);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void setIdleInt() = 0;
|
||||||
|
virtual void setLockoutInt() = 0;
|
||||||
|
virtual void setErrorInt(const char* text) = 0;
|
||||||
|
virtual void setQuitInt() = 0;
|
||||||
|
virtual void setFMInt() = 0;
|
||||||
|
|
||||||
|
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector) = 0;
|
||||||
|
virtual void writeDStarRSSIInt(unsigned char rssi);
|
||||||
|
virtual void writeDStarBERInt(float ber);
|
||||||
|
virtual void clearDStarInt() = 0;
|
||||||
|
|
||||||
|
virtual void writeDMRInt(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type) = 0;
|
||||||
|
virtual int writeDMRIntEx(unsigned int slotNo, const class CUserDBentry& src, bool group, const std::string& dst, const char* type);
|
||||||
|
virtual void writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi);
|
||||||
|
virtual void writeDMRTAInt(unsigned int slotNo, unsigned char* talkerAlias, const char* type);
|
||||||
|
virtual void writeDMRBERInt(unsigned int slotNo, float ber);
|
||||||
|
virtual void clearDMRInt(unsigned int slotNo) = 0;
|
||||||
|
|
||||||
|
virtual void writeFusionInt(const char* source, const char* dest, const char* type, const char* origin) = 0;
|
||||||
|
virtual void writeFusionRSSIInt(unsigned char rssi);
|
||||||
|
virtual void writeFusionBERInt(float ber);
|
||||||
|
virtual void clearFusionInt() = 0;
|
||||||
|
|
||||||
|
virtual void writeP25Int(const char* source, bool group, unsigned int dest, const char* type) = 0;
|
||||||
|
virtual void writeP25RSSIInt(unsigned char rssi);
|
||||||
|
virtual void writeP25BERInt(float ber);
|
||||||
|
virtual void clearP25Int() = 0;
|
||||||
|
|
||||||
|
virtual void writeNXDNInt(const char* source, bool group, unsigned int dest, const char* type) = 0;
|
||||||
|
virtual int writeNXDNIntEx(const class CUserDBentry& source, bool group, unsigned int dest, const char* type);
|
||||||
|
virtual void writeNXDNRSSIInt(unsigned char rssi);
|
||||||
|
virtual void writeNXDNBERInt(float ber);
|
||||||
|
virtual void clearNXDNInt() = 0;
|
||||||
|
|
||||||
|
virtual void writePOCSAGInt(uint32_t ric, const std::string& message) = 0;
|
||||||
|
virtual void clearPOCSAGInt() = 0;
|
||||||
|
|
||||||
|
virtual void writeCWInt() = 0;
|
||||||
|
virtual void clearCWInt() = 0;
|
||||||
|
|
||||||
|
virtual void clockInt(unsigned int ms);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
CTimer m_timer1;
|
||||||
|
CTimer m_timer2;
|
||||||
|
unsigned char m_mode1;
|
||||||
|
unsigned char m_mode2;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
19
Dockerfile
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
FROM alpine
|
||||||
|
|
||||||
|
RUN apk add --update --no-cache \
|
||||||
|
cmake \
|
||||||
|
make \
|
||||||
|
g++ \
|
||||||
|
git \
|
||||||
|
&& rm -rf /var/cache/apk/*
|
||||||
|
|
||||||
|
ADD ./ /MMDVMHost
|
||||||
|
WORKDIR /MMDVMHost
|
||||||
|
RUN make \
|
||||||
|
&& cp MMDVMHost /usr/local/bin
|
||||||
|
|
||||||
|
VOLUME /MMDVMHost
|
||||||
|
WORKDIR /MMDVMHost
|
||||||
|
|
||||||
|
CMD ["MMDVMHost", "/MMDVMHost/MMDVM.ini"]
|
||||||
|
|
100
EMB.cpp
|
@ -1,100 +0,0 @@
|
||||||
/*
|
|
||||||
* 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;
|
|
||||||
}
|
|
|
@ -5,7 +5,10 @@
|
||||||
|
|
||||||
#include "Golay24128.h"
|
#include "Golay24128.h"
|
||||||
|
|
||||||
static const unsigned int ENCODING_TABLE_23127[] = {
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
const unsigned int ENCODING_TABLE_23127[] = {
|
||||||
0x000000U, 0x0018EAU, 0x00293EU, 0x0031D4U, 0x004A96U, 0x00527CU, 0x0063A8U, 0x007B42U, 0x008DC6U, 0x00952CU,
|
0x000000U, 0x0018EAU, 0x00293EU, 0x0031D4U, 0x004A96U, 0x00527CU, 0x0063A8U, 0x007B42U, 0x008DC6U, 0x00952CU,
|
||||||
0x00A4F8U, 0x00BC12U, 0x00C750U, 0x00DFBAU, 0x00EE6EU, 0x00F684U, 0x010366U, 0x011B8CU, 0x012A58U, 0x0132B2U,
|
0x00A4F8U, 0x00BC12U, 0x00C750U, 0x00DFBAU, 0x00EE6EU, 0x00F684U, 0x010366U, 0x011B8CU, 0x012A58U, 0x0132B2U,
|
||||||
0x0149F0U, 0x01511AU, 0x0160CEU, 0x017824U, 0x018EA0U, 0x01964AU, 0x01A79EU, 0x01BF74U, 0x01C436U, 0x01DCDCU,
|
0x0149F0U, 0x01511AU, 0x0160CEU, 0x017824U, 0x018EA0U, 0x01964AU, 0x01A79EU, 0x01BF74U, 0x01C436U, 0x01DCDCU,
|
||||||
|
@ -1090,3 +1093,16 @@ unsigned int CGolay24128::decode24128(unsigned int code)
|
||||||
{
|
{
|
||||||
return decode23127(code >> 1);
|
return decode23127(code >> 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int CGolay24128::decode24128(unsigned char* bytes)
|
||||||
|
{
|
||||||
|
assert(bytes != NULL);
|
||||||
|
|
||||||
|
unsigned int code = bytes[0U];
|
||||||
|
code <<= 8;
|
||||||
|
code |= bytes[1U];
|
||||||
|
code <<= 8;
|
||||||
|
code |= bytes[2U];
|
||||||
|
|
||||||
|
return decode23127(code >> 1);
|
||||||
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ public:
|
||||||
|
|
||||||
static unsigned int decode23127(unsigned int code);
|
static unsigned int decode23127(unsigned int code);
|
||||||
static unsigned int decode24128(unsigned int code);
|
static unsigned int decode24128(unsigned int code);
|
||||||
|
static unsigned int decode24128(unsigned char* bytes);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
1114
HD44780.cpp
Normal file
174
HD44780.h
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016,2017,2018,2020 by Jonathan Naylor G4KLX & Tony Corbett G0WFV
|
||||||
|
*
|
||||||
|
* 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(HD44780_H)
|
||||||
|
#define HD44780_H
|
||||||
|
|
||||||
|
#include "Display.h"
|
||||||
|
#include "Timer.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <mcp23017.h>
|
||||||
|
#include <pcf8574.h>
|
||||||
|
|
||||||
|
enum ADAFRUIT_COLOUR {
|
||||||
|
AC_OFF,
|
||||||
|
AC_WHITE,
|
||||||
|
AC_RED,
|
||||||
|
AC_GREEN,
|
||||||
|
AC_BLUE,
|
||||||
|
AC_PURPLE,
|
||||||
|
AC_YELLOW,
|
||||||
|
AC_ICE
|
||||||
|
};
|
||||||
|
|
||||||
|
// Defines for the Adafruit Pi LCD interface board
|
||||||
|
#ifdef ADAFRUIT_DISPLAY
|
||||||
|
#define AF_BASE 100
|
||||||
|
|
||||||
|
/* Not yet used defines (for possible future use)
|
||||||
|
*
|
||||||
|
* #define AF_SELECT (AF_BASE + 0)
|
||||||
|
* #define AF_RIGHT (AF_BASE + 1)
|
||||||
|
* #define AF_DOWN (AF_BASE + 2)
|
||||||
|
* #define AF_UP (AF_BASE + 3)
|
||||||
|
* #define AF_LEFT (AF_BASE + 4)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define AF_RED (AF_BASE + 6)
|
||||||
|
#define AF_GREEN (AF_BASE + 7)
|
||||||
|
#define AF_BLUE (AF_BASE + 8)
|
||||||
|
|
||||||
|
#define AF_D3 (AF_BASE + 9)
|
||||||
|
#define AF_D2 (AF_BASE + 10)
|
||||||
|
#define AF_D1 (AF_BASE + 11)
|
||||||
|
#define AF_D0 (AF_BASE + 12)
|
||||||
|
#define AF_E (AF_BASE + 13)
|
||||||
|
#define AF_RW (AF_BASE + 14)
|
||||||
|
#define AF_RS (AF_BASE + 15)
|
||||||
|
|
||||||
|
#define AF_ON LOW
|
||||||
|
#define AF_OFF HIGH
|
||||||
|
|
||||||
|
// #define MCP23017 0x20
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Define for HD44780 connected via a PCF8574 GPIO extender
|
||||||
|
#ifdef PCF8574_DISPLAY
|
||||||
|
#define AF_BASE 100
|
||||||
|
|
||||||
|
#define AF_RS (AF_BASE + 0)
|
||||||
|
#define AF_RW (AF_BASE + 1)
|
||||||
|
#define AF_E (AF_BASE + 2)
|
||||||
|
#define AF_BL (AF_BASE + 3)
|
||||||
|
#define AF_D0 (AF_BASE + 4)
|
||||||
|
#define AF_D1 (AF_BASE + 5)
|
||||||
|
#define AF_D2 (AF_BASE + 6)
|
||||||
|
#define AF_D3 (AF_BASE + 7)
|
||||||
|
|
||||||
|
// #define PCF8574 0x27
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class CHD44780 : public CDisplay
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CHD44780(unsigned int rows, unsigned int cols, const std::string& callsign, unsigned int dmrid, const std::vector<unsigned int>& pins, unsigned int i2cAddress, bool pwm, unsigned int pwmPin, unsigned int pwmBright, unsigned int pwmDim, bool displayClock, bool utc, bool duplex);
|
||||||
|
virtual ~CHD44780();
|
||||||
|
|
||||||
|
virtual bool open();
|
||||||
|
|
||||||
|
virtual void close();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void setIdleInt();
|
||||||
|
virtual void setErrorInt(const char* text);
|
||||||
|
virtual void setLockoutInt();
|
||||||
|
virtual void setQuitInt();
|
||||||
|
virtual void setFMInt();
|
||||||
|
|
||||||
|
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
|
||||||
|
virtual void writeDStarRSSIInt(unsigned char rssi);
|
||||||
|
virtual void clearDStarInt();
|
||||||
|
|
||||||
|
virtual void writeDMRInt(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type);
|
||||||
|
virtual void writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi);
|
||||||
|
virtual void clearDMRInt(unsigned int slotNo);
|
||||||
|
|
||||||
|
virtual void writeFusionInt(const char* source, const char* dest, const char* type, const char* origin);
|
||||||
|
virtual void writeFusionRSSIInt(unsigned char rssi);
|
||||||
|
virtual void clearFusionInt();
|
||||||
|
|
||||||
|
virtual void writeP25Int(const char* source, bool group, unsigned int dest, const char* type);
|
||||||
|
virtual void writeP25RSSIInt(unsigned char rssi);
|
||||||
|
virtual void clearP25Int();
|
||||||
|
|
||||||
|
virtual void writeNXDNInt(const char* source, bool group, unsigned int dest, const char* type);
|
||||||
|
virtual void writeNXDNRSSIInt(unsigned char rssi);
|
||||||
|
virtual void clearNXDNInt();
|
||||||
|
|
||||||
|
virtual void writePOCSAGInt(uint32_t ric, const std::string& message);
|
||||||
|
virtual void clearPOCSAGInt();
|
||||||
|
|
||||||
|
virtual void writeCWInt();
|
||||||
|
virtual void clearCWInt();
|
||||||
|
|
||||||
|
virtual void clockInt(unsigned int ms);
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned int m_rows;
|
||||||
|
unsigned int m_cols;
|
||||||
|
std::string m_callsign;
|
||||||
|
unsigned int m_dmrid;
|
||||||
|
unsigned int m_rb;
|
||||||
|
unsigned int m_strb;
|
||||||
|
unsigned int m_d0;
|
||||||
|
unsigned int m_d1;
|
||||||
|
unsigned int m_d2;
|
||||||
|
unsigned int m_d3;
|
||||||
|
unsigned int m_i2cAddress;
|
||||||
|
bool m_pwm;
|
||||||
|
unsigned int m_pwmPin;
|
||||||
|
unsigned int m_pwmBright;
|
||||||
|
unsigned int m_pwmDim;
|
||||||
|
bool m_displayClock;
|
||||||
|
bool m_utc;
|
||||||
|
bool m_duplex;
|
||||||
|
int m_fd;
|
||||||
|
bool m_dmr;
|
||||||
|
CTimer m_clockDisplayTimer;
|
||||||
|
unsigned int m_rssiCount1;
|
||||||
|
unsigned int m_rssiCount2;
|
||||||
|
/*
|
||||||
|
CTimer m_dmrScrollTimer1;
|
||||||
|
CTimer m_dmrScrollTimer2;
|
||||||
|
CTimer m_dstarScrollTimer;
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef ADAFRUIT_DISPLAY
|
||||||
|
void adafruitLCDSetup();
|
||||||
|
void adafruitLCDColour(ADAFRUIT_COLOUR colour);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PCF8574_DISPLAY
|
||||||
|
void pcf8574LCDSetup();
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
107
HD44780.layouts
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
IDLE SCREEN LAYOUTS
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
16 x 2
|
||||||
|
------
|
||||||
|
|
||||||
|
With clock Without clock
|
||||||
|
---------- -------------
|
||||||
|
|
||||||
|
0 1 0 1
|
||||||
|
0123456789012345 0123456789012345
|
||||||
|
+----------------+ +----------------+
|
||||||
|
0|AAAAAA NNNNNNN| 0|AAAAAA NNNNNNN|
|
||||||
|
1|MMDVM HH:MM:SS| 1|MMDVM Idle|
|
||||||
|
+----------------+ +----------------+
|
||||||
|
|
||||||
|
40 x 2
|
||||||
|
------
|
||||||
|
|
||||||
|
With clock Without clock
|
||||||
|
---------- -------------
|
||||||
|
|
||||||
|
0 1 2 3 0 1 2 3
|
||||||
|
0123456789012345678901234567890123456789 0123456789012345678901234567890123456789
|
||||||
|
+----------------------------------------+ +----------------------------------------+
|
||||||
|
0|AAAAAA DD/MM/YY NNNNNNN| 0|AAAAAA NNNNNNN|
|
||||||
|
1|MMDVM HH:MM:SS Idle| 1|MMDVM Idle|
|
||||||
|
+----------------------------------------+ +----------------------------------------+
|
||||||
|
|
||||||
|
16 x 4
|
||||||
|
------
|
||||||
|
|
||||||
|
With clock Without clock
|
||||||
|
---------- -------------
|
||||||
|
|
||||||
|
0 1 0 1
|
||||||
|
0123456789012345 0123456789012345
|
||||||
|
+----------------+ +----------------+
|
||||||
|
0|AAAAAA NNNNNNN| 0|AAAAAA NNNNNNN|
|
||||||
|
1| DD/MM/YY | 1| |
|
||||||
|
2| HH:MM:SS | 2| |
|
||||||
|
3|MMDVM Idle| 3|MMDVM Idle|
|
||||||
|
+----------------+ +----------------+
|
||||||
|
|
||||||
|
20 x 4
|
||||||
|
------
|
||||||
|
|
||||||
|
With clock Without clock
|
||||||
|
---------- -------------
|
||||||
|
|
||||||
|
0 1 0 1
|
||||||
|
01234567890123456479 01234567890123456789
|
||||||
|
+--------------------+ +--------------------+
|
||||||
|
0|AAAAAA NNNNNNN| 0|AAAAAA NNNNNNN|
|
||||||
|
1| DD/MM/YY | 1| |
|
||||||
|
2| HH:MM:SS | 2| |
|
||||||
|
3|MMDVM Idle| 3|MMDVM Idle|
|
||||||
|
+--------------------+ +--------------------+
|
||||||
|
|
||||||
|
D-STAR LAYOUTS
|
||||||
|
-------------
|
||||||
|
|
||||||
|
16 x 2
|
||||||
|
------
|
||||||
|
|
||||||
|
0 1
|
||||||
|
0123456789012345
|
||||||
|
+----------------+
|
||||||
|
0|F AAAAAAAA/AAAAX|
|
||||||
|
1|T AAAAAAAA |
|
||||||
|
+----------------+
|
||||||
|
|
||||||
|
40 x 2
|
||||||
|
------
|
||||||
|
|
||||||
|
0 1 2 3
|
||||||
|
0123456789012345678901234567890123456789
|
||||||
|
+----------------------------------------+
|
||||||
|
0|F AAAAAAAA/AAAA X|
|
||||||
|
1|T AAAAAAAA via AAAAAAAA |
|
||||||
|
+----------------------------------------+
|
||||||
|
|
||||||
|
16 x 4
|
||||||
|
------
|
||||||
|
|
||||||
|
|
||||||
|
0 1
|
||||||
|
0123456789012345
|
||||||
|
+----------------+
|
||||||
|
0|D-Star |
|
||||||
|
1|F AAAAAAAA/AAAAX|
|
||||||
|
2|T AAAAAAAA |
|
||||||
|
3|via AAAAAAAA |
|
||||||
|
+----------------+
|
||||||
|
|
||||||
|
|
||||||
|
20 x 4
|
||||||
|
------
|
||||||
|
|
||||||
|
0 1
|
||||||
|
01234567890123456479
|
||||||
|
+--------------------+
|
||||||
|
0|D-Star |
|
||||||
|
1|F AAAAAAAA/AAAA X|
|
||||||
|
2|T AAAAAAAA |
|
||||||
|
3|via AAAAAAAA |
|
||||||
|
+--------------------+
|
127
Hamming.cpp
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -18,9 +18,68 @@
|
||||||
|
|
||||||
#include "Hamming.h"
|
#include "Hamming.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
// Hamming (15,11,3) check a boolean data array
|
// Hamming (15,11,3) check a boolean data array
|
||||||
bool CHamming::decode15113(bool* d)
|
bool CHamming::decode15113_1(bool* d)
|
||||||
{
|
{
|
||||||
|
assert(d != NULL);
|
||||||
|
|
||||||
|
// Calculate the parity it should have
|
||||||
|
bool c0 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[6];
|
||||||
|
bool c1 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[7] ^ d[8] ^ d[9];
|
||||||
|
bool c2 = d[0] ^ d[1] ^ d[4] ^ d[5] ^ d[7] ^ d[8] ^ d[10];
|
||||||
|
bool c3 = d[0] ^ d[2] ^ d[4] ^ d[6] ^ d[7] ^ d[9] ^ d[10];
|
||||||
|
|
||||||
|
unsigned char n = 0U;
|
||||||
|
n |= (c0 != d[11]) ? 0x01U : 0x00U;
|
||||||
|
n |= (c1 != d[12]) ? 0x02U : 0x00U;
|
||||||
|
n |= (c2 != d[13]) ? 0x04U : 0x00U;
|
||||||
|
n |= (c3 != d[14]) ? 0x08U : 0x00U;
|
||||||
|
|
||||||
|
switch (n)
|
||||||
|
{
|
||||||
|
// Parity bit errors
|
||||||
|
case 0x01U: d[11] = !d[11]; return true;
|
||||||
|
case 0x02U: d[12] = !d[12]; return true;
|
||||||
|
case 0x04U: d[13] = !d[13]; return true;
|
||||||
|
case 0x08U: d[14] = !d[14]; return true;
|
||||||
|
|
||||||
|
// Data bit errors
|
||||||
|
case 0x0FU: d[0] = !d[0]; return true;
|
||||||
|
case 0x07U: d[1] = !d[1]; return true;
|
||||||
|
case 0x0BU: d[2] = !d[2]; return true;
|
||||||
|
case 0x03U: d[3] = !d[3]; return true;
|
||||||
|
case 0x0DU: d[4] = !d[4]; return true;
|
||||||
|
case 0x05U: d[5] = !d[5]; return true;
|
||||||
|
case 0x09U: d[6] = !d[6]; return true;
|
||||||
|
case 0x0EU: d[7] = !d[7]; return true;
|
||||||
|
case 0x06U: d[8] = !d[8]; return true;
|
||||||
|
case 0x0AU: d[9] = !d[9]; return true;
|
||||||
|
case 0x0CU: d[10] = !d[10]; return true;
|
||||||
|
|
||||||
|
// No bit errors
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHamming::encode15113_1(bool* d)
|
||||||
|
{
|
||||||
|
assert(d != NULL);
|
||||||
|
|
||||||
|
// Calculate the checksum this row should have
|
||||||
|
d[11] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[6];
|
||||||
|
d[12] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[7] ^ d[8] ^ d[9];
|
||||||
|
d[13] = d[0] ^ d[1] ^ d[4] ^ d[5] ^ d[7] ^ d[8] ^ d[10];
|
||||||
|
d[14] = d[0] ^ d[2] ^ d[4] ^ d[6] ^ d[7] ^ d[9] ^ d[10];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hamming (15,11,3) check a boolean data array
|
||||||
|
bool CHamming::decode15113_2(bool* d)
|
||||||
|
{
|
||||||
|
assert(d != NULL);
|
||||||
|
|
||||||
// Calculate the checksum this row should have
|
// Calculate the checksum this row should have
|
||||||
bool c0 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[5] ^ d[7] ^ d[8];
|
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 c1 = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[6] ^ d[8] ^ d[9];
|
||||||
|
@ -58,8 +117,10 @@ bool CHamming::decode15113(bool* d)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CHamming::encode15113(bool* d)
|
void CHamming::encode15113_2(bool* d)
|
||||||
{
|
{
|
||||||
|
assert(d != NULL);
|
||||||
|
|
||||||
// Calculate the checksum this row should have
|
// Calculate the checksum this row should have
|
||||||
d[11] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[5] ^ d[7] ^ d[8];
|
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[12] = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[6] ^ d[8] ^ d[9];
|
||||||
|
@ -70,6 +131,8 @@ void CHamming::encode15113(bool* d)
|
||||||
// Hamming (13,9,3) check a boolean data array
|
// Hamming (13,9,3) check a boolean data array
|
||||||
bool CHamming::decode1393(bool* d)
|
bool CHamming::decode1393(bool* d)
|
||||||
{
|
{
|
||||||
|
assert(d != NULL);
|
||||||
|
|
||||||
// Calculate the checksum this column should have
|
// Calculate the checksum this column should have
|
||||||
bool c0 = d[0] ^ d[1] ^ d[3] ^ d[5] ^ d[6];
|
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 c1 = d[0] ^ d[1] ^ d[2] ^ d[4] ^ d[6] ^ d[7];
|
||||||
|
@ -107,6 +170,8 @@ bool CHamming::decode1393(bool* d)
|
||||||
|
|
||||||
void CHamming::encode1393(bool* d)
|
void CHamming::encode1393(bool* d)
|
||||||
{
|
{
|
||||||
|
assert(d != NULL);
|
||||||
|
|
||||||
// Calculate the checksum this column should have
|
// Calculate the checksum this column should have
|
||||||
d[9] = d[0] ^ d[1] ^ d[3] ^ d[5] ^ d[6];
|
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[10] = d[0] ^ d[1] ^ d[2] ^ d[4] ^ d[6] ^ d[7];
|
||||||
|
@ -114,9 +179,59 @@ void CHamming::encode1393(bool* d)
|
||||||
d[12] = d[0] ^ d[2] ^ d[4] ^ d[5] ^ d[8];
|
d[12] = d[0] ^ d[2] ^ d[4] ^ d[5] ^ d[8];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hamming (10,6,3) check a boolean data array
|
||||||
|
bool CHamming::decode1063(bool* d)
|
||||||
|
{
|
||||||
|
assert(d != NULL);
|
||||||
|
|
||||||
|
// Calculate the checksum this column should have
|
||||||
|
bool c0 = d[0] ^ d[1] ^ d[2] ^ d[5];
|
||||||
|
bool c1 = d[0] ^ d[1] ^ d[3] ^ d[5];
|
||||||
|
bool c2 = d[0] ^ d[2] ^ d[3] ^ d[4];
|
||||||
|
bool c3 = d[1] ^ d[2] ^ d[3] ^ d[4];
|
||||||
|
|
||||||
|
unsigned char n = 0x00U;
|
||||||
|
n |= (c0 != d[6]) ? 0x01U : 0x00U;
|
||||||
|
n |= (c1 != d[7]) ? 0x02U : 0x00U;
|
||||||
|
n |= (c2 != d[8]) ? 0x04U : 0x00U;
|
||||||
|
n |= (c3 != d[9]) ? 0x08U : 0x00U;
|
||||||
|
|
||||||
|
switch (n) {
|
||||||
|
// Parity bit errors
|
||||||
|
case 0x01U: d[6] = !d[6]; return true;
|
||||||
|
case 0x02U: d[7] = !d[7]; return true;
|
||||||
|
case 0x04U: d[8] = !d[8]; return true;
|
||||||
|
case 0x08U: d[9] = !d[9]; return true;
|
||||||
|
|
||||||
|
// Data bit erros
|
||||||
|
case 0x07U: d[0] = !d[0]; return true;
|
||||||
|
case 0x0BU: d[1] = !d[1]; return true;
|
||||||
|
case 0x0DU: d[2] = !d[2]; return true;
|
||||||
|
case 0x0EU: d[3] = !d[3]; return true;
|
||||||
|
case 0x0CU: d[4] = !d[4]; return true;
|
||||||
|
case 0x03U: d[5] = !d[5]; return true;
|
||||||
|
|
||||||
|
// No bit errors
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CHamming::encode1063(bool* d)
|
||||||
|
{
|
||||||
|
assert(d != NULL);
|
||||||
|
|
||||||
|
// Calculate the checksum this column should have
|
||||||
|
d[6] = d[0] ^ d[1] ^ d[2] ^ d[5];
|
||||||
|
d[7] = d[0] ^ d[1] ^ d[3] ^ d[5];
|
||||||
|
d[8] = d[0] ^ d[2] ^ d[3] ^ d[4];
|
||||||
|
d[9] = d[1] ^ d[2] ^ d[3] ^ d[4];
|
||||||
|
}
|
||||||
|
|
||||||
// A Hamming (16,11,4) Check
|
// A Hamming (16,11,4) Check
|
||||||
bool CHamming::decode16114(bool* d)
|
bool CHamming::decode16114(bool* d)
|
||||||
{
|
{
|
||||||
|
assert(d != NULL);
|
||||||
|
|
||||||
// Calculate the checksum this column should have
|
// Calculate the checksum this column should have
|
||||||
bool c0 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[5] ^ d[7] ^ d[8];
|
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 c1 = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[6] ^ d[8] ^ d[9];
|
||||||
|
@ -163,6 +278,8 @@ bool CHamming::decode16114(bool* d)
|
||||||
|
|
||||||
void CHamming::encode16114(bool* d)
|
void CHamming::encode16114(bool* d)
|
||||||
{
|
{
|
||||||
|
assert(d != NULL);
|
||||||
|
|
||||||
d[11] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[5] ^ d[7] ^ d[8];
|
d[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[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[13] = d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[7] ^ d[9] ^ d[10];
|
||||||
|
@ -173,6 +290,8 @@ void CHamming::encode16114(bool* d)
|
||||||
// A Hamming (17,12,3) Check
|
// A Hamming (17,12,3) Check
|
||||||
bool CHamming::decode17123(bool* d)
|
bool CHamming::decode17123(bool* d)
|
||||||
{
|
{
|
||||||
|
assert(d != NULL);
|
||||||
|
|
||||||
// Calculate the checksum this column should have
|
// Calculate the checksum this column should have
|
||||||
bool c0 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[6] ^ d[7] ^ d[9];
|
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 c1 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[7] ^ d[8] ^ d[10];
|
||||||
|
@ -220,6 +339,8 @@ bool CHamming::decode17123(bool* d)
|
||||||
|
|
||||||
void CHamming::encode17123(bool* d)
|
void CHamming::encode17123(bool* d)
|
||||||
{
|
{
|
||||||
|
assert(d != NULL);
|
||||||
|
|
||||||
d[12] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[6] ^ d[7] ^ d[9];
|
d[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[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[14] = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[8] ^ d[9] ^ d[11];
|
||||||
|
|
12
Hamming.h
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -21,12 +21,18 @@
|
||||||
|
|
||||||
class CHamming {
|
class CHamming {
|
||||||
public:
|
public:
|
||||||
static void encode15113(bool* d);
|
static void encode15113_1(bool* d);
|
||||||
static bool decode15113(bool* d);
|
static bool decode15113_1(bool* d);
|
||||||
|
|
||||||
|
static void encode15113_2(bool* d);
|
||||||
|
static bool decode15113_2(bool* d);
|
||||||
|
|
||||||
static void encode1393(bool* d);
|
static void encode1393(bool* d);
|
||||||
static bool decode1393(bool* d);
|
static bool decode1393(bool* d);
|
||||||
|
|
||||||
|
static void encode1063(bool* d);
|
||||||
|
static bool decode1063(bool* d);
|
||||||
|
|
||||||
static void encode16114(bool* d);
|
static void encode16114(bool* d);
|
||||||
static bool decode16114(bool* d);
|
static bool decode16114(bool* d);
|
||||||
|
|
||||||
|
|
|
@ -1,427 +0,0 @@
|
||||||
/*
|
|
||||||
* 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) {
|
|
||||||
if (m_status == RUNNING) {
|
|
||||||
LogWarning("The master is restarting, logging back in");
|
|
||||||
m_status = WAITING_LOGIN;
|
|
||||||
m_timeoutTimer.start();
|
|
||||||
m_retryTimer.start();
|
|
||||||
m_pingTimer.stop();
|
|
||||||
} else {
|
|
||||||
LogError("Login to the master has failed");
|
|
||||||
m_status = DISCONNECTED;
|
|
||||||
m_timeoutTimer.stop();
|
|
||||||
m_retryTimer.stop();
|
|
||||||
m_pingTimer.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);
|
|
||||||
}
|
|
165
I2CController.cpp
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2002-2004,2007-2011,2013,2014-2017 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 "I2CController.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
|
||||||
|
#include <setupapi.h>
|
||||||
|
#include <winioctl.h>
|
||||||
|
|
||||||
|
CI2CController::CI2CController(const std::string& device, SERIAL_SPEED speed, unsigned int address, bool assertRTS) :
|
||||||
|
CSerialController(device, speed, assertRTS),
|
||||||
|
m_address(address)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CI2CController::~CI2CController()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CI2CController::open()
|
||||||
|
{
|
||||||
|
return CSerialController::open();
|
||||||
|
}
|
||||||
|
|
||||||
|
int CI2CController::read(unsigned char* buffer, unsigned int length)
|
||||||
|
{
|
||||||
|
return CSerialController::read(buffer, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
int CI2CController::write(const unsigned char* buffer, unsigned int length)
|
||||||
|
{
|
||||||
|
return CSerialController::write(buffer, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <cerrno>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <termios.h>
|
||||||
|
#if defined(__linux__)
|
||||||
|
#include <linux/i2c-dev.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CI2CController::CI2CController(const std::string& device, SERIAL_SPEED speed, unsigned int address, bool assertRTS) :
|
||||||
|
CSerialController(device, speed, assertRTS),
|
||||||
|
m_address(address)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CI2CController::~CI2CController()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CI2CController::open()
|
||||||
|
{
|
||||||
|
assert(m_fd == -1);
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
m_fd = ::open(m_device.c_str(), O_RDWR);
|
||||||
|
if (m_fd < 0) {
|
||||||
|
LogError("Cannot open device - %s", m_device.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (::ioctl(m_fd, I2C_TENBIT, 0) < 0) {
|
||||||
|
LogError("CI2C: failed to set 7bitaddress");
|
||||||
|
::close(m_fd);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (::ioctl(m_fd, I2C_SLAVE, m_address) < 0) {
|
||||||
|
LogError("CI2C: Failed to acquire bus access/talk to slave 0x%02X", m_address);
|
||||||
|
::close(m_fd);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#warning "I2C controller supports Linux only"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CI2CController::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) {
|
||||||
|
#if defined(__linux__)
|
||||||
|
ssize_t n = ::read(m_fd, buffer + offset, 1U);
|
||||||
|
if (n < 0) {
|
||||||
|
if (errno != EAGAIN) {
|
||||||
|
LogError("Error returned from read(), errno=%d", errno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n > 0)
|
||||||
|
offset += n;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CI2CController::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 = 0U;
|
||||||
|
#if defined(__linux__)
|
||||||
|
n = ::write(m_fd, buffer + ptr, 1U);
|
||||||
|
#endif
|
||||||
|
if (n < 0) {
|
||||||
|
if (errno != EAGAIN) {
|
||||||
|
LogError("Error returned from write(), errno=%d", errno);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n > 0)
|
||||||
|
ptr += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
40
I2CController.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2002-2004,2007-2009,2011-2013,2015-2017 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 I2CController_H
|
||||||
|
#define I2CController_H
|
||||||
|
|
||||||
|
#include "SerialController.h"
|
||||||
|
|
||||||
|
class CI2CController : public CSerialController {
|
||||||
|
public:
|
||||||
|
CI2CController(const std::string& device, SERIAL_SPEED speed, unsigned int address = 0x22U, bool assertRTS = false);
|
||||||
|
virtual ~CI2CController();
|
||||||
|
|
||||||
|
virtual bool open();
|
||||||
|
|
||||||
|
virtual int read(unsigned char* buffer, unsigned int length);
|
||||||
|
|
||||||
|
virtual int write(const unsigned char* buffer, unsigned int length);
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned int m_address;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
9
ISSUES.txt
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
D-Star: On some radios, the header is not decoded correctly. It looks like frequency drift at the beginning of the transmission.
|
||||||
|
|
||||||
|
DMR: DMO mode doesn't wake up older radios like other radios do.
|
||||||
|
|
||||||
|
YSF: No known issues.
|
||||||
|
|
||||||
|
P25: Upgrade the filters, processing power in the Due permiting.
|
||||||
|
|
||||||
|
NXDN: No known issues.
|
BIN
Images/ALL.bmp
Before Width: | Height: | Size: 450 KiB |
Before Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 35 KiB |
BIN
Images/MMDVM.bmp
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 791 KiB |
Before Width: | Height: | Size: 14 KiB |
BIN
Images/NXDN.bmp
Normal file
After Width: | Height: | Size: 392 KiB |
BIN
Images/P25.bmp
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 1.8 MiB |
Before Width: | Height: | Size: 49 KiB |
BIN
Images/POCSAG.bmp
Normal file
After Width: | Height: | Size: 659 KiB |
BIN
Images/Tetra.bmp
Before Width: | Height: | Size: 148 KiB |
Before Width: | Height: | Size: 37 KiB |
BIN
Images/YSF.bmp
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 5.7 KiB |
BIN
Images/dPMR.bmp
Before Width: | Height: | Size: 148 KiB |
Before Width: | Height: | Size: 39 KiB |
846
LCDproc.cpp
Normal file
|
@ -0,0 +1,846 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016,2017,2018 by Tony Corbett G0WFV
|
||||||
|
* Copyright (C) 2018,2020 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some LCD displays include additional LEDs for status.
|
||||||
|
* If they exist, the LDCproc server will use the output command.
|
||||||
|
* If the LEDs do not exist, the command is ignored.
|
||||||
|
* to control these LEDs Below are the values for the Crystalfontz CFA-635.
|
||||||
|
* N4IRS
|
||||||
|
|
||||||
|
* LED 1 (DMR)
|
||||||
|
* Green 1 0000 0001
|
||||||
|
* Red 16 0001 0000
|
||||||
|
* Yellow 17 0001 0001
|
||||||
|
|
||||||
|
* LED 2 (P25)
|
||||||
|
* Green 2 0000 0010
|
||||||
|
* Red 32 0010 0000
|
||||||
|
* Yellow 34 0010 0010
|
||||||
|
|
||||||
|
* LED 3 (Fusion)
|
||||||
|
* Green 4 0000 0100
|
||||||
|
* Red 64 0100 0000
|
||||||
|
* Yellow 68 1000 0100
|
||||||
|
|
||||||
|
* LED 4 (D-Star)
|
||||||
|
* Green 8 0000 1000
|
||||||
|
* Red 128 1000 0000
|
||||||
|
* Yellow 136 1000 1000
|
||||||
|
|
||||||
|
* LED 5 (NXDN)
|
||||||
|
* Green 16 0001 0000
|
||||||
|
* Red 255 1111 1111
|
||||||
|
* Yellow 255 1111 1111
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "LCDproc.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <clocale>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
#if !defined(_WIN32) && !defined(_WIN64)
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#else
|
||||||
|
#include <winsock.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define BUFFER_MAX_LEN 128
|
||||||
|
|
||||||
|
int m_socketfd;
|
||||||
|
char m_buffer[BUFFER_MAX_LEN];
|
||||||
|
fd_set m_readfds, m_writefds;
|
||||||
|
struct timeval m_timeout;
|
||||||
|
int m_recvsize;
|
||||||
|
unsigned int m_rows(0);
|
||||||
|
unsigned int m_cols(0);
|
||||||
|
bool m_screensDefined(false);
|
||||||
|
bool m_connected(false);
|
||||||
|
|
||||||
|
char m_displayBuffer1[BUFFER_MAX_LEN];
|
||||||
|
char m_displayBuffer2[BUFFER_MAX_LEN];
|
||||||
|
|
||||||
|
const unsigned int DSTAR_RSSI_COUNT = 3U; // 3 * 420ms = 1260ms
|
||||||
|
const unsigned int DMR_RSSI_COUNT = 4U; // 4 * 360ms = 1440ms
|
||||||
|
const unsigned int YSF_RSSI_COUNT = 13U; // 13 * 100ms = 1300ms
|
||||||
|
const unsigned int P25_RSSI_COUNT = 7U; // 7 * 180ms = 1260ms
|
||||||
|
const unsigned int NXDN_RSSI_COUNT = 28U; // 28 * 40ms = 1120ms
|
||||||
|
|
||||||
|
CLCDproc::CLCDproc(std::string address, unsigned int port, unsigned int localPort, const std::string& callsign, unsigned int dmrid, bool displayClock, bool utc, bool duplex, bool dimOnIdle) :
|
||||||
|
CDisplay(),
|
||||||
|
m_address(address),
|
||||||
|
m_port(port),
|
||||||
|
m_localPort(localPort),
|
||||||
|
m_callsign(callsign),
|
||||||
|
m_dmrid(dmrid),
|
||||||
|
m_displayClock(displayClock),
|
||||||
|
m_utc(utc),
|
||||||
|
m_duplex(duplex),
|
||||||
|
//m_duplex(true), // uncomment to force duplex display for testing!
|
||||||
|
m_dimOnIdle(dimOnIdle),
|
||||||
|
m_dmr(false),
|
||||||
|
m_clockDisplayTimer(1000U, 0U, 250U), // Update the clock display every 250ms
|
||||||
|
m_rssiCount1(0U),
|
||||||
|
m_rssiCount2(0U)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CLCDproc::~CLCDproc()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CLCDproc::open()
|
||||||
|
{
|
||||||
|
const char *server;
|
||||||
|
unsigned int port, localPort;
|
||||||
|
struct sockaddr_in serverAddress, clientAddress;
|
||||||
|
struct hostent *h;
|
||||||
|
|
||||||
|
server = m_address.c_str();
|
||||||
|
port = m_port;
|
||||||
|
localPort = m_localPort;
|
||||||
|
|
||||||
|
|
||||||
|
/* Create TCP socket */
|
||||||
|
m_socketfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (m_socketfd == -1) {
|
||||||
|
LogError("LCDproc, failed to create socket");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sets client address (random port - need to specify manual port from ini file?) */
|
||||||
|
clientAddress.sin_family = AF_INET;
|
||||||
|
clientAddress.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
//clientAddress.sin_port = htons(0);
|
||||||
|
clientAddress.sin_port = htons(localPort);
|
||||||
|
|
||||||
|
/* Bind the address to the socket */
|
||||||
|
if (bind(m_socketfd, (struct sockaddr *)&clientAddress, sizeof(clientAddress)) == -1) {
|
||||||
|
LogError("LCDproc, error whilst binding address");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lookup the hostname address */
|
||||||
|
h = gethostbyname(server);
|
||||||
|
|
||||||
|
/* Sets server address */
|
||||||
|
serverAddress.sin_family = h->h_addrtype;
|
||||||
|
memcpy((char*)&serverAddress.sin_addr.s_addr, h->h_addr_list[0], h->h_length);
|
||||||
|
serverAddress.sin_port = htons(port);
|
||||||
|
|
||||||
|
if (connect(m_socketfd, (struct sockaddr * )&serverAddress, sizeof(serverAddress))==-1) {
|
||||||
|
LogError("LCDproc, cannot connect to server");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
socketPrintf(m_socketfd, "hello"); // Login to the LCD server
|
||||||
|
socketPrintf(m_socketfd, "output 0"); // Clear all LEDs
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLCDproc::setIdleInt()
|
||||||
|
{
|
||||||
|
m_clockDisplayTimer.start(); // Start the clock display in IDLE only
|
||||||
|
|
||||||
|
if (m_screensDefined) {
|
||||||
|
socketPrintf(m_socketfd, "screen_set DStar -priority hidden");
|
||||||
|
socketPrintf(m_socketfd, "screen_set DMR -priority hidden");
|
||||||
|
socketPrintf(m_socketfd, "screen_set YSF -priority hidden");
|
||||||
|
socketPrintf(m_socketfd, "screen_set P25 -priority hidden");
|
||||||
|
socketPrintf(m_socketfd, "screen_set NXDN -priority hidden");
|
||||||
|
socketPrintf(m_socketfd, "widget_set Status Status %u %u Idle", m_cols - 3, m_rows);
|
||||||
|
socketPrintf(m_socketfd, "output 0"); // Clear all LEDs
|
||||||
|
}
|
||||||
|
|
||||||
|
m_dmr = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLCDproc::setErrorInt(const char* text)
|
||||||
|
{
|
||||||
|
assert(text != NULL);
|
||||||
|
|
||||||
|
m_clockDisplayTimer.stop(); // Stop the clock display
|
||||||
|
|
||||||
|
if (m_screensDefined) {
|
||||||
|
socketPrintf(m_socketfd, "screen_set DStar -priority hidden");
|
||||||
|
socketPrintf(m_socketfd, "screen_set DMR -priority hidden");
|
||||||
|
socketPrintf(m_socketfd, "screen_set YSF -priority hidden");
|
||||||
|
socketPrintf(m_socketfd, "screen_set P25 -priority hidden");
|
||||||
|
socketPrintf(m_socketfd, "screen_set NXDN -priority hidden");
|
||||||
|
socketPrintf(m_socketfd, "widget_set Status Status %u %u Error", m_cols - 4, m_rows);
|
||||||
|
socketPrintf(m_socketfd, "output 0"); // Clear all LEDs
|
||||||
|
}
|
||||||
|
|
||||||
|
m_dmr = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLCDproc::setLockoutInt()
|
||||||
|
{
|
||||||
|
m_clockDisplayTimer.stop(); // Stop the clock display
|
||||||
|
|
||||||
|
if (m_screensDefined) {
|
||||||
|
socketPrintf(m_socketfd, "screen_set DStar -priority hidden");
|
||||||
|
socketPrintf(m_socketfd, "screen_set DMR -priority hidden");
|
||||||
|
socketPrintf(m_socketfd, "screen_set YSF -priority hidden");
|
||||||
|
socketPrintf(m_socketfd, "screen_set P25 -priority hidden");
|
||||||
|
socketPrintf(m_socketfd, "screen_set NXDN -priority hidden");
|
||||||
|
socketPrintf(m_socketfd, "widget_set Status Status %u %u Lockout", m_cols - 6, m_rows);
|
||||||
|
socketPrintf(m_socketfd, "output 0"); // Clear all LEDs
|
||||||
|
}
|
||||||
|
|
||||||
|
m_dmr = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// LED 4 Green 8 Red 128 Yellow 136
|
||||||
|
|
||||||
|
void CLCDproc::setQuitInt()
|
||||||
|
{
|
||||||
|
m_clockDisplayTimer.stop(); // Stop the clock display
|
||||||
|
|
||||||
|
if (m_screensDefined) {
|
||||||
|
socketPrintf(m_socketfd, "screen_set DStar -priority hidden");
|
||||||
|
socketPrintf(m_socketfd, "screen_set DMR -priority hidden");
|
||||||
|
socketPrintf(m_socketfd, "screen_set YSF -priority hidden");
|
||||||
|
socketPrintf(m_socketfd, "screen_set P25 -priority hidden");
|
||||||
|
socketPrintf(m_socketfd, "screen_set NXDN -priority hidden");
|
||||||
|
socketPrintf(m_socketfd, "widget_set Status Status %u %u Stopped", m_cols - 6, m_rows);
|
||||||
|
socketPrintf(m_socketfd, "output 0"); // Clear all LEDs
|
||||||
|
}
|
||||||
|
|
||||||
|
m_dmr = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLCDproc::setFMInt()
|
||||||
|
{
|
||||||
|
m_clockDisplayTimer.stop(); // Stop the clock display
|
||||||
|
|
||||||
|
if (m_screensDefined) {
|
||||||
|
socketPrintf(m_socketfd, "screen_set DStar -priority hidden");
|
||||||
|
socketPrintf(m_socketfd, "screen_set DMR -priority hidden");
|
||||||
|
socketPrintf(m_socketfd, "screen_set YSF -priority hidden");
|
||||||
|
socketPrintf(m_socketfd, "screen_set P25 -priority hidden");
|
||||||
|
socketPrintf(m_socketfd, "screen_set NXDN -priority hidden");
|
||||||
|
socketPrintf(m_socketfd, "widget_set Status Status %u %u FM", m_cols - 6, m_rows);
|
||||||
|
socketPrintf(m_socketfd, "output 0"); // Clear all LEDs
|
||||||
|
}
|
||||||
|
|
||||||
|
m_dmr = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLCDproc::writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector)
|
||||||
|
{
|
||||||
|
assert(my1 != NULL);
|
||||||
|
assert(my2 != NULL);
|
||||||
|
assert(your != NULL);
|
||||||
|
assert(type != NULL);
|
||||||
|
assert(reflector != NULL);
|
||||||
|
|
||||||
|
m_clockDisplayTimer.stop(); // Stop the clock display
|
||||||
|
|
||||||
|
socketPrintf(m_socketfd, "screen_set DStar -priority foreground");
|
||||||
|
socketPrintf(m_socketfd, "widget_set DStar Mode 1 1 \"D-Star\"");
|
||||||
|
|
||||||
|
::sprintf(m_displayBuffer1, "%.8s", your);
|
||||||
|
|
||||||
|
char *p = m_displayBuffer1;
|
||||||
|
for (; *p; ++p) {
|
||||||
|
if (*p == ' ')
|
||||||
|
*p = '_';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(reflector, " ") != 0)
|
||||||
|
sprintf(m_displayBuffer2, " via %.8s", reflector);
|
||||||
|
else
|
||||||
|
memset(m_displayBuffer2, 0, BUFFER_MAX_LEN);
|
||||||
|
|
||||||
|
if (m_rows == 2U) {
|
||||||
|
socketPrintf(m_socketfd, "widget_set DStar Line2 1 2 %u 2 h 3 \"%.8s/%.4s to %s%s\"", m_cols - 1, my1, my2, m_displayBuffer1, m_displayBuffer2);
|
||||||
|
} else {
|
||||||
|
socketPrintf(m_socketfd, "widget_set DStar Line2 1 2 %u 2 h 3 \"%.8s/%.4s\"", m_cols - 1, my1, my2);
|
||||||
|
socketPrintf(m_socketfd, "widget_set DStar Line3 1 3 %u 3 h 3 \"%s%s\"", m_cols - 1, m_displayBuffer1, m_displayBuffer2);
|
||||||
|
socketPrintf(m_socketfd, "output 128"); // Set LED4 color red
|
||||||
|
}
|
||||||
|
|
||||||
|
m_dmr = false;
|
||||||
|
m_rssiCount1 = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLCDproc::writeDStarRSSIInt(unsigned char rssi)
|
||||||
|
{
|
||||||
|
if (m_rssiCount1 == 0U) {
|
||||||
|
socketPrintf(m_socketfd, "widget_set DStar Line4 1 4 %u 4 h 3 \"-%3udBm\"", m_cols - 1, rssi);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_rssiCount1++;
|
||||||
|
if (m_rssiCount1 >= DSTAR_RSSI_COUNT)
|
||||||
|
m_rssiCount1 = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLCDproc::clearDStarInt()
|
||||||
|
{
|
||||||
|
m_clockDisplayTimer.stop(); // Stop the clock display
|
||||||
|
|
||||||
|
socketPrintf(m_socketfd, "widget_set DStar Line2 1 2 15 2 h 3 \"Listening\"");
|
||||||
|
socketPrintf(m_socketfd, "widget_set DStar Line3 1 3 15 3 h 3 \"\"");
|
||||||
|
socketPrintf(m_socketfd, "widget_set DStar Line4 1 4 15 4 h 3 \"\"");
|
||||||
|
socketPrintf(m_socketfd, "output 8"); // Set LED4 color green
|
||||||
|
}
|
||||||
|
|
||||||
|
// LED 1 Green 1 Red 16 Yellow 17
|
||||||
|
|
||||||
|
void CLCDproc::writeDMRInt(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type)
|
||||||
|
{
|
||||||
|
assert(type != NULL);
|
||||||
|
|
||||||
|
if (!m_dmr) {
|
||||||
|
m_clockDisplayTimer.stop(); // Stop the clock display
|
||||||
|
|
||||||
|
socketPrintf(m_socketfd, "screen_set DMR -priority foreground");
|
||||||
|
|
||||||
|
if (m_duplex) {
|
||||||
|
if (m_rows > 2U)
|
||||||
|
socketPrintf(m_socketfd, "widget_set DMR Mode 1 1 DMR");
|
||||||
|
if (slotNo == 1U)
|
||||||
|
socketPrintf(m_socketfd, "widget_set DMR Slot2 3 %u %u %u h 3 \"Listening\"", m_rows / 2 + 1, m_cols - 1, m_rows / 2 + 1);
|
||||||
|
else
|
||||||
|
socketPrintf(m_socketfd, "widget_set DMR Slot1 3 %u %u %u h 3 \"Listening\"", m_rows / 2, m_cols - 1, m_rows / 2);
|
||||||
|
} else {
|
||||||
|
socketPrintf(m_socketfd, "widget_set DMR Slot1_ 1 %u \"\"", m_rows / 2);
|
||||||
|
socketPrintf(m_socketfd, "widget_set DMR Slot2_ 1 %u \"\"", m_rows / 2 + 1);
|
||||||
|
|
||||||
|
socketPrintf(m_socketfd, "widget_set DMR Slot1 1 %u %u %u h 3 \"Listening\"", m_rows / 2, m_cols - 1, m_rows / 2);
|
||||||
|
socketPrintf(m_socketfd, "widget_set DMR Slot2 1 %u %u %u h 3 \"\"", m_rows / 2 + 1, m_cols - 1, m_rows / 2 + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_duplex) {
|
||||||
|
if (m_rows > 2U)
|
||||||
|
socketPrintf(m_socketfd, "widget_set DMR Mode 1 1 DMR");
|
||||||
|
|
||||||
|
if (slotNo == 1U)
|
||||||
|
socketPrintf(m_socketfd, "widget_set DMR Slot1 3 %u %u %u h 3 \"%s > %s%s\"", m_rows / 2, m_cols - 1, m_rows / 2, src.c_str(), group ? "TG" : "", dst.c_str());
|
||||||
|
else
|
||||||
|
socketPrintf(m_socketfd, "widget_set DMR Slot2 3 %u %u %u h 3 \"%s > %s%s\"", m_rows / 2 + 1, m_cols - 1, m_rows / 2 + 1, src.c_str(), group ? "TG" : "", dst.c_str());
|
||||||
|
} else {
|
||||||
|
socketPrintf(m_socketfd, "widget_set DMR Mode 1 1 DMR");
|
||||||
|
|
||||||
|
if (m_rows == 2U) {
|
||||||
|
socketPrintf(m_socketfd, "widget_set DMR Slot1 1 2 %u 2 h 3 \"%s > %s%s\"", m_cols - 1, src.c_str(), group ? "TG" : "", dst.c_str());
|
||||||
|
} else {
|
||||||
|
socketPrintf(m_socketfd, "widget_set DMR Slot1 1 2 %u 2 h 3 \"%s >\"", m_cols - 1, src.c_str());
|
||||||
|
socketPrintf(m_socketfd, "widget_set DMR Slot2 1 3 %u 3 h 3 \"%s%s\"", m_cols - 1, group ? "TG" : "", dst.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
socketPrintf(m_socketfd, "output 16"); // Set LED1 color red
|
||||||
|
m_dmr = true;
|
||||||
|
m_rssiCount1 = 0U;
|
||||||
|
m_rssiCount2 = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLCDproc::writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi)
|
||||||
|
{
|
||||||
|
if (m_rows > 2) {
|
||||||
|
if (slotNo == 1U) {
|
||||||
|
if (m_rssiCount1 == 0U)
|
||||||
|
socketPrintf(m_socketfd, "widget_set DMR Slot1RSSI %u %u -%3udBm", 1, 4, rssi);
|
||||||
|
|
||||||
|
m_rssiCount1++;
|
||||||
|
|
||||||
|
if (m_rssiCount1 >= DMR_RSSI_COUNT)
|
||||||
|
m_rssiCount1 = 0U;
|
||||||
|
} else {
|
||||||
|
if (m_rssiCount2 == 0U)
|
||||||
|
socketPrintf(m_socketfd, "widget_set DMR Slot2RSSI %u %u -%3udBm", (m_cols / 2) + 1, 4, rssi);
|
||||||
|
|
||||||
|
m_rssiCount2++;
|
||||||
|
|
||||||
|
if (m_rssiCount2 >= DMR_RSSI_COUNT)
|
||||||
|
m_rssiCount2 = 0U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLCDproc::clearDMRInt(unsigned int slotNo)
|
||||||
|
{
|
||||||
|
m_clockDisplayTimer.stop(); // Stop the clock display
|
||||||
|
|
||||||
|
if (m_duplex) {
|
||||||
|
if (slotNo == 1U) {
|
||||||
|
socketPrintf(m_socketfd, "widget_set DMR Slot1 3 %u %u %u h 3 \"Listening\"", m_rows / 2, m_cols - 1, m_rows / 2);
|
||||||
|
socketPrintf(m_socketfd, "widget_set DMR Slot1RSSI %u %u %*.s", 1, 4, m_cols / 2, " ");
|
||||||
|
} else {
|
||||||
|
socketPrintf(m_socketfd, "widget_set DMR Slot2 3 %u %u %u h 3 \"Listening\"", m_rows / 2 + 1, m_cols - 1, m_rows / 2 + 1);
|
||||||
|
socketPrintf(m_socketfd, "widget_set DMR Slot2RSSI %u %u %*.s", (m_cols / 2) + 1, 4, m_cols / 2, " ");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
socketPrintf(m_socketfd, "widget_set DMR Slot1 1 2 15 2 h 3 \"Listening\"");
|
||||||
|
socketPrintf(m_socketfd, "widget_set DMR Slot2 1 3 15 3 h 3 \"\"");
|
||||||
|
socketPrintf(m_socketfd, "widget_set DMR Slot2RSSI %u %u %*.s", (m_cols / 2) + 1, 4, m_cols / 2, " ");
|
||||||
|
}
|
||||||
|
socketPrintf(m_socketfd, "output 1"); // Set LED1 color green
|
||||||
|
}
|
||||||
|
|
||||||
|
// LED 3 Green 4 Red 64 Yellow 68
|
||||||
|
|
||||||
|
void CLCDproc::writeFusionInt(const char* source, const char* dest, const char* type, const char* origin)
|
||||||
|
{
|
||||||
|
assert(source != NULL);
|
||||||
|
assert(dest != NULL);
|
||||||
|
assert(type != NULL);
|
||||||
|
assert(origin != NULL);
|
||||||
|
|
||||||
|
m_clockDisplayTimer.stop(); // Stop the clock display
|
||||||
|
|
||||||
|
socketPrintf(m_socketfd, "screen_set YSF -priority foreground");
|
||||||
|
socketPrintf(m_socketfd, "widget_set YSF Mode 1 1 \"System Fusion\"");
|
||||||
|
|
||||||
|
if (m_rows == 2U) {
|
||||||
|
socketPrintf(m_socketfd, "widget_set YSF Line2 1 2 15 2 h 3 \"%.10s > %s%u\"", source, dest);
|
||||||
|
} else {
|
||||||
|
socketPrintf(m_socketfd, "widget_set YSF Line2 1 2 15 2 h 3 \"%.10s >\"", source);
|
||||||
|
socketPrintf(m_socketfd, "widget_set YSF Line3 1 3 15 3 h 3 \"%s%u\"", dest);
|
||||||
|
socketPrintf(m_socketfd, "output 64"); // Set LED3 color red
|
||||||
|
}
|
||||||
|
|
||||||
|
m_dmr = false;
|
||||||
|
m_rssiCount1 = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLCDproc::writeFusionRSSIInt(unsigned char rssi)
|
||||||
|
{
|
||||||
|
if (m_rssiCount1 == 0U) {
|
||||||
|
socketPrintf(m_socketfd, "widget_set YSF Line4 1 4 %u 4 h 3 \"-%3udBm\"", m_cols - 1, rssi);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_rssiCount1++;
|
||||||
|
if (m_rssiCount1 >= YSF_RSSI_COUNT)
|
||||||
|
m_rssiCount1 = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLCDproc::clearFusionInt()
|
||||||
|
{
|
||||||
|
m_clockDisplayTimer.stop(); // Stop the clock display
|
||||||
|
|
||||||
|
socketPrintf(m_socketfd, "widget_set YSF Line2 1 2 15 2 h 3 \"Listening\"");
|
||||||
|
socketPrintf(m_socketfd, "widget_set YSF Line3 1 3 15 3 h 3 \"\"");
|
||||||
|
socketPrintf(m_socketfd, "widget_set YSF Line4 1 4 15 4 h 3 \"\"");
|
||||||
|
socketPrintf(m_socketfd, "output 4"); // Set LED3 color green
|
||||||
|
}
|
||||||
|
|
||||||
|
// LED 2 Green 2 Red 32 Yellow 34
|
||||||
|
|
||||||
|
void CLCDproc::writeP25Int(const char* source, bool group, unsigned int dest, const char* type)
|
||||||
|
{
|
||||||
|
assert(source != NULL);
|
||||||
|
assert(type != NULL);
|
||||||
|
|
||||||
|
m_clockDisplayTimer.stop(); // Stop the clock display
|
||||||
|
|
||||||
|
socketPrintf(m_socketfd, "screen_set P25 -priority foreground");
|
||||||
|
socketPrintf(m_socketfd, "widget_set P25 Mode 1 1 P25");
|
||||||
|
|
||||||
|
if (m_rows == 2U) {
|
||||||
|
socketPrintf(m_socketfd, "widget_set P25 Line2 1 2 15 2 h 3 \"%.10s > %s%u\"", source, group ? "TG" : "", dest);
|
||||||
|
} else {
|
||||||
|
socketPrintf(m_socketfd, "widget_set P25 Line2 1 2 15 2 h 3 \"%.10s >\"", source);
|
||||||
|
socketPrintf(m_socketfd, "widget_set P25 Line3 1 3 15 3 h 3 \"%s%u\"", group ? "TG" : "", dest);
|
||||||
|
socketPrintf(m_socketfd, "output 32"); // Set LED2 color red
|
||||||
|
}
|
||||||
|
|
||||||
|
m_dmr = false;
|
||||||
|
m_rssiCount1 = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLCDproc::writeP25RSSIInt(unsigned char rssi)
|
||||||
|
{
|
||||||
|
if (m_rssiCount1 == 0U) {
|
||||||
|
socketPrintf(m_socketfd, "widget_set P25 Line4 1 4 %u 4 h 3 \"-%3udBm\"", m_cols - 1, rssi);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_rssiCount1++;
|
||||||
|
if (m_rssiCount1 >= P25_RSSI_COUNT)
|
||||||
|
m_rssiCount1 = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLCDproc::clearP25Int()
|
||||||
|
{
|
||||||
|
m_clockDisplayTimer.stop(); // Stop the clock display
|
||||||
|
|
||||||
|
socketPrintf(m_socketfd, "widget_set P25 Line2 1 2 15 2 h 3 \"Listening\"");
|
||||||
|
socketPrintf(m_socketfd, "widget_set P25 Line3 1 3 15 3 h 3 \"\"");
|
||||||
|
socketPrintf(m_socketfd, "widget_set P25 Line4 1 4 15 4 h 3 \"\"");
|
||||||
|
socketPrintf(m_socketfd, "output 2"); // Set LED2 color green
|
||||||
|
}
|
||||||
|
|
||||||
|
// LED 5 Green 16 Red 255 Yellow 255
|
||||||
|
|
||||||
|
void CLCDproc::writeNXDNInt(const char* source, bool group, unsigned int dest, const char* type)
|
||||||
|
{
|
||||||
|
assert(source != NULL);
|
||||||
|
assert(type != NULL);
|
||||||
|
|
||||||
|
m_clockDisplayTimer.stop(); // Stop the clock display
|
||||||
|
|
||||||
|
socketPrintf(m_socketfd, "screen_set NXDN -priority foreground");
|
||||||
|
socketPrintf(m_socketfd, "widget_set NXDN Mode 1 1 NXDN");
|
||||||
|
|
||||||
|
if (m_rows == 2U) {
|
||||||
|
socketPrintf(m_socketfd, "widget_set NXDN Line2 1 2 15 2 h 3 \"%.10s > %s%u\"", source, group ? "TG" : "", dest);
|
||||||
|
} else {
|
||||||
|
socketPrintf(m_socketfd, "widget_set NXDN Line2 1 2 15 2 h 3 \"%.10s >\"", source);
|
||||||
|
socketPrintf(m_socketfd, "widget_set NXDN Line3 1 3 15 3 h 3 \"%s%u\"", group ? "TG" : "", dest);
|
||||||
|
socketPrintf(m_socketfd, "output 255"); // Set LED5 color red
|
||||||
|
}
|
||||||
|
|
||||||
|
m_dmr = false;
|
||||||
|
m_rssiCount1 = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLCDproc::writeNXDNRSSIInt(unsigned char rssi)
|
||||||
|
{
|
||||||
|
if (m_rssiCount1 == 0U) {
|
||||||
|
socketPrintf(m_socketfd, "widget_set NXDN Line4 1 4 %u 4 h 3 \"-%3udBm\"", m_cols - 1, rssi);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_rssiCount1++;
|
||||||
|
if (m_rssiCount1 >= NXDN_RSSI_COUNT)
|
||||||
|
m_rssiCount1 = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLCDproc::clearNXDNInt()
|
||||||
|
{
|
||||||
|
m_clockDisplayTimer.stop(); // Stop the clock display
|
||||||
|
|
||||||
|
socketPrintf(m_socketfd, "widget_set NXDN Line2 1 2 15 2 h 3 \"Listening\"");
|
||||||
|
socketPrintf(m_socketfd, "widget_set NXDN Line3 1 3 15 3 h 3 \"\"");
|
||||||
|
socketPrintf(m_socketfd, "widget_set NXDN Line4 1 4 15 4 h 3 \"\"");
|
||||||
|
socketPrintf(m_socketfd, "output 16"); // Set LED5 color green
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLCDproc::writePOCSAGInt(uint32_t ric, const std::string& message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLCDproc::clearPOCSAGInt()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLCDproc::writeCWInt()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLCDproc::clearCWInt()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLCDproc::clockInt(unsigned int ms)
|
||||||
|
{
|
||||||
|
m_clockDisplayTimer.clock(ms);
|
||||||
|
|
||||||
|
// Idle clock display
|
||||||
|
if (m_displayClock && m_clockDisplayTimer.isRunning() && m_clockDisplayTimer.hasExpired()) {
|
||||||
|
time_t currentTime;
|
||||||
|
struct tm *Time;
|
||||||
|
time(¤tTime);
|
||||||
|
|
||||||
|
if (m_utc)
|
||||||
|
Time = gmtime(¤tTime);
|
||||||
|
else
|
||||||
|
Time = localtime(¤tTime);
|
||||||
|
|
||||||
|
setlocale(LC_TIME, "");
|
||||||
|
strftime(m_displayBuffer1, 128, "%X", Time); // Time
|
||||||
|
strftime(m_displayBuffer2, 128, "%x", Time); // Date
|
||||||
|
|
||||||
|
if (m_cols < 26U && m_rows == 2U) {
|
||||||
|
socketPrintf(m_socketfd, "widget_set Status Time %u 2 \"%s%s\"", m_cols - 9, strlen(m_displayBuffer1) > 8 ? "" : " ", m_displayBuffer1);
|
||||||
|
} else {
|
||||||
|
socketPrintf(m_socketfd, "widget_set Status Time %u %u \"%s\"", (m_cols - (strlen(m_displayBuffer1) == 8 ? 6 : 8)) / 2, m_rows / 2, m_displayBuffer1);
|
||||||
|
socketPrintf(m_socketfd, "widget_set Status Date %u %u \"%s\"", (m_cols - (strlen(m_displayBuffer1) == 8 ? 6 : 8)) / 2, m_rows / 2 + 1, m_displayBuffer2);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_clockDisplayTimer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// We must set all this information on each select we do
|
||||||
|
FD_ZERO(&m_readfds); // empty readfds
|
||||||
|
|
||||||
|
// Then we put all the descriptors we want to wait for in a mask = m_readfds
|
||||||
|
FD_SET(m_socketfd, &m_readfds);
|
||||||
|
|
||||||
|
// Timeout, we will stop waiting for information
|
||||||
|
m_timeout.tv_sec = 0;
|
||||||
|
m_timeout.tv_usec = 0;
|
||||||
|
|
||||||
|
/* The first parameter is the biggest descriptor + 1. The first one was 0, so
|
||||||
|
* every other descriptor will be bigger
|
||||||
|
*
|
||||||
|
* readfds = &m_readfds
|
||||||
|
* writefds = we are not waiting for writefds
|
||||||
|
* exceptfds = we are not waiting for exception fds
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (select(m_socketfd + 1, &m_readfds, NULL, NULL, &m_timeout) == -1)
|
||||||
|
LogError("LCDproc, error on select");
|
||||||
|
|
||||||
|
// If something was received from the server...
|
||||||
|
if (FD_ISSET(m_socketfd, &m_readfds)) {
|
||||||
|
m_recvsize = recv(m_socketfd, m_buffer, BUFFER_MAX_LEN, 0);
|
||||||
|
|
||||||
|
if (m_recvsize == -1)
|
||||||
|
LogError("LCDproc, cannot receive information");
|
||||||
|
|
||||||
|
m_buffer[m_recvsize] = '\0';
|
||||||
|
|
||||||
|
char *argv[256];
|
||||||
|
size_t len = strlen(m_buffer);
|
||||||
|
|
||||||
|
// Now split the string into tokens...
|
||||||
|
int argc = 0;
|
||||||
|
int newtoken = 1;
|
||||||
|
|
||||||
|
for (size_t i = 0U; i < len; i++) {
|
||||||
|
switch (m_buffer[i]) {
|
||||||
|
case ' ':
|
||||||
|
newtoken = 1;
|
||||||
|
m_buffer[i] = 0;
|
||||||
|
break;
|
||||||
|
default: /* regular chars, keep tokenizing */
|
||||||
|
if (newtoken)
|
||||||
|
argv[argc++] = m_buffer + i;
|
||||||
|
newtoken = 0;
|
||||||
|
break;
|
||||||
|
case '\0':
|
||||||
|
case '\n':
|
||||||
|
m_buffer[i] = 0;
|
||||||
|
if (argc > 0) {
|
||||||
|
if (0 == strcmp(argv[0], "listen")) {
|
||||||
|
LogDebug("LCDproc, the %s screen is displayed", argv[1]);
|
||||||
|
} else if (0 == strcmp(argv[0], "ignore")) {
|
||||||
|
LogDebug("LCDproc, the %s screen is hidden", argv[1]);
|
||||||
|
} else if (0 == strcmp(argv[0], "key")) {
|
||||||
|
LogDebug("LCDproc, Key %s", argv[1]);
|
||||||
|
} else if (0 == strcmp(argv[0], "menu")) {
|
||||||
|
} else if (0 == strcmp(argv[0], "connect")) {
|
||||||
|
// connect LCDproc 0.5.7 protocol 0.3 lcd wid 16 hgt 2 cellwid 5 cellhgt 8
|
||||||
|
int a;
|
||||||
|
|
||||||
|
for (a = 1; a < argc; a++) {
|
||||||
|
if (0 == strcmp(argv[a], "wid"))
|
||||||
|
m_cols = atoi(argv[++a]);
|
||||||
|
else if (0 == strcmp(argv[a], "hgt"))
|
||||||
|
m_rows = atoi(argv[++a]);
|
||||||
|
else if (0 == strcmp(argv[a], "cellwid")) {
|
||||||
|
//lcd_cellwid = atoi(argv[++a]);
|
||||||
|
} else if (0 == strcmp(argv[a], "cellhgt")) {
|
||||||
|
//lcd_cellhgt = atoi(argv[++a]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_connected = true;
|
||||||
|
socketPrintf(m_socketfd, "client_set -name MMDVMHost");
|
||||||
|
} else if (0 == strcmp(argv[0], "bye")) {
|
||||||
|
//close the socket- todo
|
||||||
|
} else if (0 == strcmp(argv[0], "success")) {
|
||||||
|
//LogDebug("LCDproc, command successful");
|
||||||
|
} else if (0 == strcmp(argv[0], "huh?")) {
|
||||||
|
sprintf(m_displayBuffer1, "LCDproc, command failed:");
|
||||||
|
sprintf(m_displayBuffer2, " ");
|
||||||
|
|
||||||
|
int j;
|
||||||
|
for (j = 1; j < argc; j++) {
|
||||||
|
strcat(m_displayBuffer1, m_displayBuffer2);
|
||||||
|
strcat(m_displayBuffer1, argv[j]);
|
||||||
|
}
|
||||||
|
LogDebug("%s", m_displayBuffer1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restart tokenizing */
|
||||||
|
argc = 0;
|
||||||
|
newtoken = 1;
|
||||||
|
break;
|
||||||
|
} /* switch( m_buffer[i] ) */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_screensDefined && m_connected)
|
||||||
|
defineScreens();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLCDproc::close()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int CLCDproc::socketPrintf(int fd, const char *format, ...)
|
||||||
|
{
|
||||||
|
char buf[BUFFER_MAX_LEN];
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, format);
|
||||||
|
int size = vsnprintf(buf, BUFFER_MAX_LEN, format, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
if (size < 0) {
|
||||||
|
LogError("LCDproc, socketPrintf: vsnprintf failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size > BUFFER_MAX_LEN)
|
||||||
|
LogWarning("LCDproc, socketPrintf: vsnprintf truncated message");
|
||||||
|
|
||||||
|
FD_ZERO(&m_writefds); // empty writefds
|
||||||
|
FD_SET(m_socketfd, &m_writefds);
|
||||||
|
|
||||||
|
m_timeout.tv_sec = 0;
|
||||||
|
m_timeout.tv_usec = 0;
|
||||||
|
|
||||||
|
if (select(m_socketfd + 1, NULL, &m_writefds, NULL, &m_timeout) == -1)
|
||||||
|
LogError("LCDproc, error on select");
|
||||||
|
|
||||||
|
if (FD_ISSET(m_socketfd, &m_writefds)) {
|
||||||
|
if (send(m_socketfd, buf, int(strlen(buf) + 1U), 0) == -1) {
|
||||||
|
LogError("LCDproc, cannot send data");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CLCDproc::defineScreens()
|
||||||
|
{
|
||||||
|
// The Status Screen
|
||||||
|
|
||||||
|
socketPrintf(m_socketfd, "screen_add Status");
|
||||||
|
socketPrintf(m_socketfd, "screen_set Status -name Status -heartbeat on -priority info -backlight %s", m_dimOnIdle ? "off" : "on");
|
||||||
|
|
||||||
|
socketPrintf(m_socketfd, "widget_add Status Callsign string");
|
||||||
|
socketPrintf(m_socketfd, "widget_add Status DMRNumber string");
|
||||||
|
socketPrintf(m_socketfd, "widget_add Status Title string");
|
||||||
|
socketPrintf(m_socketfd, "widget_add Status Status string");
|
||||||
|
socketPrintf(m_socketfd, "widget_add Status Time string");
|
||||||
|
socketPrintf(m_socketfd, "widget_add Status Date string");
|
||||||
|
|
||||||
|
socketPrintf(m_socketfd, "widget_set Status Callsign 1 1 %s", m_callsign.c_str());
|
||||||
|
socketPrintf(m_socketfd, "widget_set Status DMRNumber %u 1 %u", m_cols - 7, m_dmrid);
|
||||||
|
socketPrintf(m_socketfd, "widget_set Status Title 1 %u MMDVM", m_rows);
|
||||||
|
socketPrintf(m_socketfd, "widget_set Status Status %u %u Idle", m_cols - 3, m_rows);
|
||||||
|
|
||||||
|
// The DStar Screen
|
||||||
|
|
||||||
|
socketPrintf(m_socketfd, "screen_add DStar");
|
||||||
|
socketPrintf(m_socketfd, "screen_set DStar -name DStar -heartbeat on -priority hidden -backlight on");
|
||||||
|
|
||||||
|
socketPrintf(m_socketfd, "widget_add DStar Mode string");
|
||||||
|
socketPrintf(m_socketfd, "widget_add DStar Line2 scroller");
|
||||||
|
socketPrintf(m_socketfd, "widget_add DStar Line3 scroller");
|
||||||
|
socketPrintf(m_socketfd, "widget_add DStar Line4 scroller");
|
||||||
|
|
||||||
|
/* Do we need to pre-populate the values??
|
||||||
|
socketPrintf(m_socketfd, "widget_set DStar Line2 1 2 15 2 h 3 \"Listening\"");
|
||||||
|
socketPrintf(m_socketfd, "widget_set DStar Line3 1 3 15 3 h 3 \"\"");
|
||||||
|
socketPrintf(m_socketfd, "widget_set DStar Line4 1 4 15 4 h 3 \"\"");
|
||||||
|
*/
|
||||||
|
|
||||||
|
// The DMR Screen
|
||||||
|
|
||||||
|
socketPrintf(m_socketfd, "screen_add DMR");
|
||||||
|
socketPrintf(m_socketfd, "screen_set DMR -name DMR -heartbeat on -priority hidden -backlight on");
|
||||||
|
|
||||||
|
socketPrintf(m_socketfd, "widget_add DMR Mode string");
|
||||||
|
socketPrintf(m_socketfd, "widget_add DMR Slot1_ string");
|
||||||
|
socketPrintf(m_socketfd, "widget_add DMR Slot2_ string");
|
||||||
|
socketPrintf(m_socketfd, "widget_add DMR Slot1 scroller");
|
||||||
|
socketPrintf(m_socketfd, "widget_add DMR Slot2 scroller");
|
||||||
|
socketPrintf(m_socketfd, "widget_add DMR Slot1RSSI string");
|
||||||
|
socketPrintf(m_socketfd, "widget_add DMR Slot2RSSI string");
|
||||||
|
|
||||||
|
/* Do we need to pre-populate the values??
|
||||||
|
socketPrintf(m_socketfd, "widget_set DMR Slot1_ 1 %u 1", m_rows / 2);
|
||||||
|
socketPrintf(m_socketfd, "widget_set DMR Slot2_ 1 %u 2", m_rows / 2 + 1);
|
||||||
|
socketPrintf(m_socketfd, "widget_set DMR Slot1 3 1 15 1 h 3 \"Listening\"");
|
||||||
|
socketPrintf(m_socketfd, "widget_set DMR Slot2 3 2 15 2 h 3 \"Listening\"");
|
||||||
|
*/
|
||||||
|
|
||||||
|
// The YSF Screen
|
||||||
|
|
||||||
|
socketPrintf(m_socketfd, "screen_add YSF");
|
||||||
|
socketPrintf(m_socketfd, "screen_set YSF -name YSF -heartbeat on -priority hidden -backlight on");
|
||||||
|
|
||||||
|
socketPrintf(m_socketfd, "widget_add YSF Mode string");
|
||||||
|
socketPrintf(m_socketfd, "widget_add YSF Line2 scroller");
|
||||||
|
socketPrintf(m_socketfd, "widget_add YSF Line3 scroller");
|
||||||
|
socketPrintf(m_socketfd, "widget_add YSF Line4 scroller");
|
||||||
|
|
||||||
|
/* Do we need to pre-populate the values??
|
||||||
|
socketPrintf(m_socketfd, "widget_set YSF Line2 2 1 15 1 h 3 \"Listening\"");
|
||||||
|
socketPrintf(m_socketfd, "widget_set YSF Line3 3 1 15 1 h 3 \" \"");
|
||||||
|
socketPrintf(m_socketfd, "widget_set YSF Line4 4 2 15 2 h 3 \" \"");
|
||||||
|
*/
|
||||||
|
|
||||||
|
// The P25 Screen
|
||||||
|
|
||||||
|
socketPrintf(m_socketfd, "screen_add P25");
|
||||||
|
socketPrintf(m_socketfd, "screen_set P25 -name P25 -heartbeat on -priority hidden -backlight on");
|
||||||
|
|
||||||
|
socketPrintf(m_socketfd, "widget_add P25 Mode string");
|
||||||
|
socketPrintf(m_socketfd, "widget_add P25 Line2 scroller");
|
||||||
|
socketPrintf(m_socketfd, "widget_add P25 Line3 scroller");
|
||||||
|
socketPrintf(m_socketfd, "widget_add P25 Line4 scroller");
|
||||||
|
|
||||||
|
/* Do we need to pre-populate the values??
|
||||||
|
socketPrintf(m_socketfd, "widget_set P25 Line3 2 1 15 1 h 3 \"Listening\"");
|
||||||
|
socketPrintf(m_socketfd, "widget_set P25 Line3 3 1 15 1 h 3 \" \"");
|
||||||
|
socketPrintf(m_socketfd, "widget_set P25 Line4 4 2 15 2 h 3 \" \"");
|
||||||
|
*/
|
||||||
|
|
||||||
|
// The NXDN Screen
|
||||||
|
|
||||||
|
socketPrintf(m_socketfd, "screen_add NXDN");
|
||||||
|
socketPrintf(m_socketfd, "screen_set NXDN -name NXDN -heartbeat on -priority hidden -backlight on");
|
||||||
|
|
||||||
|
socketPrintf(m_socketfd, "widget_add NXDN Mode string");
|
||||||
|
socketPrintf(m_socketfd, "widget_add NXDN Line2 scroller");
|
||||||
|
socketPrintf(m_socketfd, "widget_add NXDN Line3 scroller");
|
||||||
|
socketPrintf(m_socketfd, "widget_add NXDN Line4 scroller");
|
||||||
|
|
||||||
|
/* Do we need to pre-populate the values??
|
||||||
|
socketPrintf(m_socketfd, "widget_set NXDN Line3 2 1 15 1 h 3 \"Listening\"");
|
||||||
|
socketPrintf(m_socketfd, "widget_set NXDN Line3 3 1 15 1 h 3 \" \"");
|
||||||
|
socketPrintf(m_socketfd, "widget_set NXDN Line4 4 2 15 2 h 3 \" \"");
|
||||||
|
*/
|
||||||
|
|
||||||
|
m_screensDefined = true;
|
||||||
|
}
|
92
LCDproc.h
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016,2017 by Tony Corbett G0WFV
|
||||||
|
* Copyright (C) 2018,2020 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(LCDproc_H)
|
||||||
|
#define LCDproc_H
|
||||||
|
|
||||||
|
#include "Display.h"
|
||||||
|
#include "Timer.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class CLCDproc : public CDisplay
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CLCDproc(std::string address, unsigned int port, unsigned int localPort, const std::string& callsign, unsigned int dmrid, bool displayClock, bool utc, bool duplex, bool dimOnIdle);
|
||||||
|
virtual ~CLCDproc();
|
||||||
|
|
||||||
|
virtual bool open();
|
||||||
|
|
||||||
|
virtual void close();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void setIdleInt();
|
||||||
|
virtual void setErrorInt(const char* text);
|
||||||
|
virtual void setLockoutInt();
|
||||||
|
virtual void setQuitInt();
|
||||||
|
virtual void setFMInt();
|
||||||
|
|
||||||
|
virtual void writeDStarInt(const char* my1, const char* my2, const char* your, const char* type, const char* reflector);
|
||||||
|
virtual void writeDStarRSSIInt(unsigned char rssi);
|
||||||
|
virtual void clearDStarInt();
|
||||||
|
|
||||||
|
virtual void writeDMRInt(unsigned int slotNo, const std::string& src, bool group, const std::string& dst, const char* type);
|
||||||
|
virtual void writeDMRRSSIInt(unsigned int slotNo, unsigned char rssi);
|
||||||
|
virtual void clearDMRInt(unsigned int slotNo);
|
||||||
|
|
||||||
|
virtual void writeFusionInt(const char* source, const char* dest, const char* type, const char* origin);
|
||||||
|
virtual void writeFusionRSSIInt(unsigned char rssi);
|
||||||
|
virtual void clearFusionInt();
|
||||||
|
|
||||||
|
virtual void writeP25Int(const char* source, bool group, unsigned int dest, const char* type);
|
||||||
|
virtual void writeP25RSSIInt(unsigned char rssi);
|
||||||
|
virtual void clearP25Int();
|
||||||
|
|
||||||
|
virtual void writeNXDNInt(const char* source, bool group, unsigned int dest, const char* type);
|
||||||
|
virtual void writeNXDNRSSIInt(unsigned char rssi);
|
||||||
|
virtual void clearNXDNInt();
|
||||||
|
|
||||||
|
virtual void writePOCSAGInt(uint32_t ric, const std::string& message);
|
||||||
|
virtual void clearPOCSAGInt();
|
||||||
|
|
||||||
|
virtual void writeCWInt();
|
||||||
|
virtual void clearCWInt();
|
||||||
|
|
||||||
|
virtual void clockInt(unsigned int ms);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_address;
|
||||||
|
unsigned int m_port;
|
||||||
|
unsigned int m_localPort;
|
||||||
|
std::string m_callsign;
|
||||||
|
unsigned int m_dmrid;
|
||||||
|
bool m_displayClock;
|
||||||
|
bool m_utc;
|
||||||
|
bool m_duplex;
|
||||||
|
bool m_dimOnIdle;
|
||||||
|
bool m_dmr;
|
||||||
|
CTimer m_clockDisplayTimer;
|
||||||
|
unsigned int m_rssiCount1;
|
||||||
|
unsigned int m_rssiCount2;
|
||||||
|
|
||||||
|
int socketPrintf(int fd, const char *format, ...);
|
||||||
|
void defineScreens();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
107
Log.cpp
|
@ -18,20 +18,28 @@
|
||||||
|
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
#include <Windows.h>
|
||||||
|
#else
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
static std::string m_path;
|
static unsigned int m_fileLevel = 2U;
|
||||||
static std::string m_root;
|
static std::string m_filePath;
|
||||||
|
static std::string m_fileRoot;
|
||||||
|
|
||||||
static FILE* m_fpLog = NULL;
|
static FILE* m_fpLog = NULL;
|
||||||
|
static bool m_daemon = false;
|
||||||
|
|
||||||
static bool m_display = true;
|
static unsigned int m_displayLevel = 2U;
|
||||||
|
|
||||||
static unsigned int m_level = 2U;
|
|
||||||
|
|
||||||
static struct tm m_tm;
|
static struct tm m_tm;
|
||||||
|
|
||||||
|
@ -39,6 +47,11 @@ static char LEVELS[] = " DMIWEF";
|
||||||
|
|
||||||
static bool LogOpen()
|
static bool LogOpen()
|
||||||
{
|
{
|
||||||
|
bool status = false;
|
||||||
|
|
||||||
|
if (m_fileLevel == 0U)
|
||||||
|
return true;
|
||||||
|
|
||||||
time_t now;
|
time_t now;
|
||||||
::time(&now);
|
::time(&now);
|
||||||
|
|
||||||
|
@ -52,24 +65,35 @@ static bool LogOpen()
|
||||||
::fclose(m_fpLog);
|
::fclose(m_fpLog);
|
||||||
}
|
}
|
||||||
|
|
||||||
char filename[50U];
|
char filename[100U];
|
||||||
#if defined(_WIN32) || defined(_WIN64)
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
::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);
|
::sprintf(filename, "%s\\%s-%04d-%02d-%02d.log", m_filePath.c_str(), m_fileRoot.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
|
||||||
#else
|
#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);
|
::sprintf(filename, "%s/%s-%04d-%02d-%02d.log", m_filePath.c_str(), m_fileRoot.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_fpLog = ::fopen(filename, "a+t");
|
if ((m_fpLog = ::fopen(filename, "a+t")) != NULL)
|
||||||
m_tm = *tm;
|
{
|
||||||
|
status = true;
|
||||||
|
|
||||||
return m_fpLog != NULL;
|
#if !defined(_WIN32) && !defined(_WIN64)
|
||||||
|
if (m_daemon)
|
||||||
|
dup2(fileno(m_fpLog), fileno(stderr));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LogInitialise(const std::string& path, const std::string& root, bool display)
|
m_tm = *tm;
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LogInitialise(bool daemon, const std::string& filePath, const std::string& fileRoot, unsigned int fileLevel, unsigned int displayLevel)
|
||||||
{
|
{
|
||||||
m_path = path;
|
m_filePath = filePath;
|
||||||
m_root = root;
|
m_fileRoot = fileRoot;
|
||||||
m_display = display;
|
m_fileLevel = fileLevel;
|
||||||
|
m_displayLevel = displayLevel;
|
||||||
|
m_daemon = daemon;
|
||||||
return ::LogOpen();
|
return ::LogOpen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,44 +103,43 @@ void LogFinalise()
|
||||||
::fclose(m_fpLog);
|
::fclose(m_fpLog);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogSetLevel(unsigned int level)
|
|
||||||
{
|
|
||||||
m_level = level;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Log(unsigned int level, const char* fmt, ...)
|
void Log(unsigned int level, const char* fmt, ...)
|
||||||
{
|
{
|
||||||
assert(level < 7U);
|
|
||||||
assert(fmt != NULL);
|
assert(fmt != NULL);
|
||||||
|
|
||||||
if (level < m_level)
|
char buffer[300U];
|
||||||
return;
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
SYSTEMTIME st;
|
||||||
|
::GetSystemTime(&st);
|
||||||
|
|
||||||
|
::sprintf(buffer, "%c: %04u-%02u-%02u %02u:%02u:%02u.%03u ", LEVELS[level], st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
|
||||||
|
#else
|
||||||
|
struct timeval now;
|
||||||
|
::gettimeofday(&now, NULL);
|
||||||
|
|
||||||
|
struct tm* tm = ::gmtime(&now.tv_sec);
|
||||||
|
|
||||||
|
::sprintf(buffer, "%c: %04d-%02d-%02d %02d:%02d:%02d.%03lu ", LEVELS[level], tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec / 1000U);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
va_list vl;
|
||||||
|
va_start(vl, fmt);
|
||||||
|
|
||||||
|
::vsprintf(buffer + ::strlen(buffer), fmt, vl);
|
||||||
|
|
||||||
|
va_end(vl);
|
||||||
|
|
||||||
|
if (level >= m_fileLevel && m_fileLevel != 0U) {
|
||||||
bool ret = ::LogOpen();
|
bool ret = ::LogOpen();
|
||||||
if (!ret)
|
if (!ret)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
time_t now;
|
::fprintf(m_fpLog, "%s\n", buffer);
|
||||||
::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);
|
::fflush(m_fpLog);
|
||||||
|
}
|
||||||
|
|
||||||
if (m_display) {
|
if (level >= m_displayLevel && m_displayLevel != 0U) {
|
||||||
::fprintf(stdout, "\n");
|
::fprintf(stdout, "%s\n", buffer);
|
||||||
::fflush(stdout);
|
::fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
6
Log.h
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -30,9 +30,7 @@
|
||||||
|
|
||||||
extern void Log(unsigned int level, const char* fmt, ...);
|
extern void Log(unsigned int level, const char* fmt, ...);
|
||||||
|
|
||||||
extern bool LogInitialise(const std::string& path, const std::string& root, bool display);
|
extern bool LogInitialise(bool daemon, const std::string& filePath, const std::string& fileRoot, unsigned int fileLevel, unsigned int displayLevel);
|
||||||
extern void LogFinalise();
|
extern void LogFinalise();
|
||||||
|
|
||||||
extern void LogSetLevel(unsigned int level);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
253
MMDVM.ini
|
@ -1,9 +1,13 @@
|
||||||
[General]
|
[General]
|
||||||
Callsign=G9BF
|
Callsign=G9BF
|
||||||
|
Id=123456
|
||||||
Timeout=180
|
Timeout=180
|
||||||
Duplex=1
|
Duplex=1
|
||||||
ModeHang=10
|
# ModeHang=10
|
||||||
|
RFModeHang=10
|
||||||
|
NetModeHang=3
|
||||||
Display=None
|
Display=None
|
||||||
|
Daemon=0
|
||||||
|
|
||||||
[Info]
|
[Info]
|
||||||
RXFrequency=435000000
|
RXFrequency=435000000
|
||||||
|
@ -18,54 +22,277 @@ URL=www.google.co.uk
|
||||||
|
|
||||||
[Log]
|
[Log]
|
||||||
# Logging levels, 0=No logging
|
# Logging levels, 0=No logging
|
||||||
Level=1
|
DisplayLevel=1
|
||||||
Path=.
|
FileLevel=1
|
||||||
Root=MMDVM
|
FilePath=.
|
||||||
Display=1
|
FileRoot=MMDVM
|
||||||
|
|
||||||
|
[CW Id]
|
||||||
|
Enable=1
|
||||||
|
Time=10
|
||||||
|
# Callsign=
|
||||||
|
|
||||||
|
[DMR Id Lookup]
|
||||||
|
File=DMRIds.dat
|
||||||
|
Time=24
|
||||||
|
|
||||||
|
[NXDN Id Lookup]
|
||||||
|
File=NXDN.csv
|
||||||
|
Time=24
|
||||||
|
|
||||||
[Modem]
|
[Modem]
|
||||||
# Port=/dev/ttyACM0
|
# Port=/dev/ttyACM0
|
||||||
Port=\\.\COM3
|
# Port=/dev/ttyAMA0
|
||||||
|
Port=\\.\COM4
|
||||||
|
Protocol=uart
|
||||||
|
# Address=0x22
|
||||||
TXInvert=1
|
TXInvert=1
|
||||||
RXInvert=0
|
RXInvert=0
|
||||||
PTTInvert=0
|
PTTInvert=0
|
||||||
TXDelay=100
|
TXDelay=100
|
||||||
|
RXOffset=0
|
||||||
|
TXOffset=0
|
||||||
|
DMRDelay=0
|
||||||
RXLevel=50
|
RXLevel=50
|
||||||
TXLevel=50
|
TXLevel=50
|
||||||
|
RXDCOffset=0
|
||||||
|
TXDCOffset=0
|
||||||
|
RFLevel=100
|
||||||
|
# CWIdTXLevel=50
|
||||||
|
# D-StarTXLevel=50
|
||||||
|
# DMRTXLevel=50
|
||||||
|
# YSFTXLevel=50
|
||||||
|
# P25TXLevel=50
|
||||||
|
# NXDNTXLevel=50
|
||||||
|
# POCSAGTXLevel=50
|
||||||
|
# FMTXLevel=50
|
||||||
|
RSSIMappingFile=RSSI.dat
|
||||||
|
Trace=0
|
||||||
Debug=0
|
Debug=0
|
||||||
|
|
||||||
|
[Transparent Data]
|
||||||
|
Enable=0
|
||||||
|
RemoteAddress=127.0.0.1
|
||||||
|
RemotePort=40094
|
||||||
|
LocalPort=40095
|
||||||
|
# SendFrameType=0
|
||||||
|
|
||||||
|
[UMP]
|
||||||
|
Enable=0
|
||||||
|
# Port=\\.\COM4
|
||||||
|
Port=/dev/ttyACM1
|
||||||
|
|
||||||
[D-Star]
|
[D-Star]
|
||||||
Enable=1
|
Enable=1
|
||||||
Module=C
|
Module=C
|
||||||
|
SelfOnly=0
|
||||||
|
AckReply=1
|
||||||
|
AckTime=750
|
||||||
|
AckMessage=0
|
||||||
|
ErrorReply=1
|
||||||
|
RemoteGateway=0
|
||||||
|
# ModeHang=10
|
||||||
|
|
||||||
[DMR]
|
[DMR]
|
||||||
Enable=1
|
Enable=1
|
||||||
Beacons=1
|
Beacons=0
|
||||||
Id=123456
|
BeaconInterval=60
|
||||||
|
BeaconDuration=3
|
||||||
ColorCode=1
|
ColorCode=1
|
||||||
|
SelfOnly=0
|
||||||
|
EmbeddedLCOnly=0
|
||||||
|
DumpTAData=1
|
||||||
|
# Prefixes=234,235
|
||||||
|
# Slot1TGWhiteList=
|
||||||
|
# Slot2TGWhiteList=
|
||||||
|
CallHang=3
|
||||||
|
TXHang=4
|
||||||
|
# ModeHang=10
|
||||||
|
# OVCM Values, 0=off, 1=rx_on, 2=tx_on, 3=both_on
|
||||||
|
# OVCM=0
|
||||||
|
|
||||||
[System Fusion]
|
[System Fusion]
|
||||||
Enable=1
|
Enable=1
|
||||||
|
LowDeviation=0
|
||||||
|
SelfOnly=0
|
||||||
|
TXHang=4
|
||||||
|
#DGID=1
|
||||||
|
RemoteGateway=0
|
||||||
|
# ModeHang=10
|
||||||
|
|
||||||
|
[P25]
|
||||||
|
Enable=1
|
||||||
|
NAC=293
|
||||||
|
SelfOnly=0
|
||||||
|
OverrideUIDCheck=0
|
||||||
|
RemoteGateway=0
|
||||||
|
TXHang=5
|
||||||
|
# ModeHang=10
|
||||||
|
|
||||||
|
[NXDN]
|
||||||
|
Enable=1
|
||||||
|
RAN=1
|
||||||
|
SelfOnly=0
|
||||||
|
RemoteGateway=0
|
||||||
|
TXHang=5
|
||||||
|
# ModeHang=10
|
||||||
|
|
||||||
|
[POCSAG]
|
||||||
|
Enable=1
|
||||||
|
Frequency=439987500
|
||||||
|
|
||||||
|
[FM]
|
||||||
|
Enable=1
|
||||||
|
# Callsign=G4KLX
|
||||||
|
CallsignSpeed=20
|
||||||
|
CallsignFrequency=1000
|
||||||
|
CallsignTime=10
|
||||||
|
CallsignHoldoff=0
|
||||||
|
CallsignHighLevel=50
|
||||||
|
CallsignLowLevel=20
|
||||||
|
CallsignAtStart=1
|
||||||
|
CallsignAtEnd=1
|
||||||
|
CallsignAtLatch=0
|
||||||
|
RFAck=K
|
||||||
|
ExtAck=N
|
||||||
|
AckSpeed=20
|
||||||
|
AckFrequency=1750
|
||||||
|
AckMinTime=4
|
||||||
|
AckDelay=1000
|
||||||
|
AckLevel=50
|
||||||
|
# Timeout=180
|
||||||
|
TimeoutLevel=80
|
||||||
|
CTCSSFrequency=88.4
|
||||||
|
CTCSSThreshold=30
|
||||||
|
# CTCSSHighThreshold=30
|
||||||
|
# CTCSSLowThreshold=20
|
||||||
|
CTCSSLevel=20
|
||||||
|
KerchunkTime=0
|
||||||
|
HangTime=7
|
||||||
|
UseCOS=1
|
||||||
|
COSInvert=0
|
||||||
|
RFAudioBoost=1
|
||||||
|
MaxDevLevel=90
|
||||||
|
ExtAudioBoost=1
|
||||||
|
|
||||||
[D-Star Network]
|
[D-Star Network]
|
||||||
Enable=1
|
Enable=1
|
||||||
GatewayAddress=127.0.0.1
|
GatewayAddress=127.0.0.1
|
||||||
GatewayPort=20010
|
GatewayPort=20010
|
||||||
LocalPort=20011
|
LocalPort=20011
|
||||||
|
# ModeHang=3
|
||||||
Debug=0
|
Debug=0
|
||||||
|
|
||||||
[DMR Network]
|
[DMR Network]
|
||||||
Enable=1
|
Enable=1
|
||||||
Address=44.131.4.1
|
Address=44.131.4.1
|
||||||
Port=62031
|
Port=62031
|
||||||
|
Jitter=360
|
||||||
|
# Local=62032
|
||||||
Password=PASSWORD
|
Password=PASSWORD
|
||||||
Debug=1
|
# Options=
|
||||||
|
Slot1=1
|
||||||
|
Slot2=1
|
||||||
|
# ModeHang=3
|
||||||
|
Debug=0
|
||||||
|
|
||||||
[System Fusion Network]
|
[System Fusion Network]
|
||||||
Enable=0
|
Enable=1
|
||||||
Address=44.131.4.1
|
LocalAddress=127.0.0.1
|
||||||
Port=32768
|
LocalPort=3200
|
||||||
Debug=1
|
GatewayAddress=127.0.0.1
|
||||||
|
GatewayPort=4200
|
||||||
|
# ModeHang=3
|
||||||
|
Debug=0
|
||||||
|
|
||||||
|
[P25 Network]
|
||||||
|
Enable=1
|
||||||
|
GatewayAddress=127.0.0.1
|
||||||
|
GatewayPort=42020
|
||||||
|
LocalPort=32010
|
||||||
|
# ModeHang=3
|
||||||
|
Debug=0
|
||||||
|
|
||||||
|
[NXDN Network]
|
||||||
|
Enable=1
|
||||||
|
Protocol=Icom
|
||||||
|
LocalAddress=127.0.0.1
|
||||||
|
LocalPort=14021
|
||||||
|
GatewayAddress=127.0.0.1
|
||||||
|
GatewayPort=14020
|
||||||
|
# ModeHang=3
|
||||||
|
Debug=0
|
||||||
|
|
||||||
|
[POCSAG Network]
|
||||||
|
Enable=1
|
||||||
|
LocalAddress=127.0.0.1
|
||||||
|
LocalPort=3800
|
||||||
|
GatewayAddress=127.0.0.1
|
||||||
|
GatewayPort=4800
|
||||||
|
# ModeHang=3
|
||||||
|
Debug=0
|
||||||
|
|
||||||
[TFT Serial]
|
[TFT Serial]
|
||||||
|
# Port=modem
|
||||||
Port=/dev/ttyAMA0
|
Port=/dev/ttyAMA0
|
||||||
|
Brightness=50
|
||||||
|
|
||||||
|
[HD44780]
|
||||||
|
Rows=2
|
||||||
|
Columns=16
|
||||||
|
|
||||||
|
# For basic HD44780 displays (4-bit connection)
|
||||||
|
# rs, strb, d0, d1, d2, d3
|
||||||
|
Pins=11,10,0,1,2,3
|
||||||
|
|
||||||
|
# Device address for I2C
|
||||||
|
I2CAddress=0x20
|
||||||
|
|
||||||
|
# PWM backlight
|
||||||
|
PWM=0
|
||||||
|
PWMPin=21
|
||||||
|
PWMBright=100
|
||||||
|
PWMDim=16
|
||||||
|
|
||||||
|
DisplayClock=1
|
||||||
|
UTC=0
|
||||||
|
|
||||||
|
[Nextion]
|
||||||
|
# Port=modem
|
||||||
|
Port=/dev/ttyAMA0
|
||||||
|
Brightness=50
|
||||||
|
DisplayClock=1
|
||||||
|
UTC=0
|
||||||
|
#Screen Layout: 0=G4KLX 2=ON7LDS
|
||||||
|
ScreenLayout=2
|
||||||
|
IdleBrightness=20
|
||||||
|
|
||||||
|
[OLED]
|
||||||
|
Type=3
|
||||||
|
Brightness=0
|
||||||
|
Invert=0
|
||||||
|
Scroll=1
|
||||||
|
Rotate=0
|
||||||
|
Cast=0
|
||||||
|
LogoScreensaver=1
|
||||||
|
|
||||||
|
[LCDproc]
|
||||||
|
Address=localhost
|
||||||
|
Port=13666
|
||||||
|
#LocalPort=13667
|
||||||
|
DimOnIdle=0
|
||||||
|
DisplayClock=1
|
||||||
|
UTC=0
|
||||||
|
|
||||||
|
[Lock File]
|
||||||
|
Enable=0
|
||||||
|
File=/tmp/MMDVM_Active.lck
|
||||||
|
|
||||||
|
[Mobile GPS]
|
||||||
|
Enable=0
|
||||||
|
Address=127.0.0.1
|
||||||
|
Port=7834
|
||||||
|
|
||||||
|
[Remote Control]
|
||||||
|
Enable=0
|
||||||
|
Port=7642
|
||||||
|
|
2043
MMDVMHost.cpp
86
MMDVMHost.h
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2015 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015-2020 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -19,13 +19,32 @@
|
||||||
#if !defined(MMDVMHOST_H)
|
#if !defined(MMDVMHOST_H)
|
||||||
#define MMDVMHOST_H
|
#define MMDVMHOST_H
|
||||||
|
|
||||||
#include "HomebrewDMRIPSC.h"
|
#include "RemoteControl.h"
|
||||||
|
#include "POCSAGNetwork.h"
|
||||||
|
#include "POCSAGControl.h"
|
||||||
|
#include "DStarNetwork.h"
|
||||||
|
#include "NXDNNetwork.h"
|
||||||
|
#include "DStarControl.h"
|
||||||
|
#include "DMRControl.h"
|
||||||
|
#include "YSFControl.h"
|
||||||
|
#include "P25Control.h"
|
||||||
|
#include "NXDNControl.h"
|
||||||
|
#include "NXDNLookup.h"
|
||||||
|
#include "YSFNetwork.h"
|
||||||
|
#include "P25Network.h"
|
||||||
|
#include "DMRNetwork.h"
|
||||||
|
#include "DMRLookup.h"
|
||||||
|
#include "MobileGPS.h"
|
||||||
#include "Display.h"
|
#include "Display.h"
|
||||||
|
#include "Timer.h"
|
||||||
#include "Modem.h"
|
#include "Modem.h"
|
||||||
#include "Conf.h"
|
#include "Conf.h"
|
||||||
|
#include "UMP.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class CMMDVMHost
|
class CMMDVMHost
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -37,16 +56,73 @@ public:
|
||||||
private:
|
private:
|
||||||
CConf m_conf;
|
CConf m_conf;
|
||||||
CModem* m_modem;
|
CModem* m_modem;
|
||||||
CHomebrewDMRIPSC* m_dmrNetwork;
|
CDStarControl* m_dstar;
|
||||||
IDisplay* m_display;
|
CDMRControl* m_dmr;
|
||||||
|
CYSFControl* m_ysf;
|
||||||
|
CP25Control* m_p25;
|
||||||
|
CNXDNControl* m_nxdn;
|
||||||
|
CPOCSAGControl* m_pocsag;
|
||||||
|
CDStarNetwork* m_dstarNetwork;
|
||||||
|
CDMRNetwork* m_dmrNetwork;
|
||||||
|
CYSFNetwork* m_ysfNetwork;
|
||||||
|
CP25Network* m_p25Network;
|
||||||
|
INXDNNetwork* m_nxdnNetwork;
|
||||||
|
CPOCSAGNetwork* m_pocsagNetwork;
|
||||||
|
CDisplay* m_display;
|
||||||
|
CUMP* m_ump;
|
||||||
|
unsigned char m_mode;
|
||||||
|
unsigned int m_dstarRFModeHang;
|
||||||
|
unsigned int m_dmrRFModeHang;
|
||||||
|
unsigned int m_ysfRFModeHang;
|
||||||
|
unsigned int m_p25RFModeHang;
|
||||||
|
unsigned int m_nxdnRFModeHang;
|
||||||
|
unsigned int m_dstarNetModeHang;
|
||||||
|
unsigned int m_dmrNetModeHang;
|
||||||
|
unsigned int m_ysfNetModeHang;
|
||||||
|
unsigned int m_p25NetModeHang;
|
||||||
|
unsigned int m_nxdnNetModeHang;
|
||||||
|
unsigned int m_pocsagNetModeHang;
|
||||||
|
CTimer m_modeTimer;
|
||||||
|
CTimer m_dmrTXTimer;
|
||||||
|
CTimer m_cwIdTimer;
|
||||||
|
bool m_duplex;
|
||||||
|
unsigned int m_timeout;
|
||||||
bool m_dstarEnabled;
|
bool m_dstarEnabled;
|
||||||
bool m_dmrEnabled;
|
bool m_dmrEnabled;
|
||||||
bool m_ysfEnabled;
|
bool m_ysfEnabled;
|
||||||
|
bool m_p25Enabled;
|
||||||
|
bool m_nxdnEnabled;
|
||||||
|
bool m_pocsagEnabled;
|
||||||
|
bool m_fmEnabled;
|
||||||
|
unsigned int m_cwIdTime;
|
||||||
|
CDMRLookup* m_dmrLookup;
|
||||||
|
CNXDNLookup* m_nxdnLookup;
|
||||||
|
std::string m_callsign;
|
||||||
|
unsigned int m_id;
|
||||||
|
std::string m_cwCallsign;
|
||||||
|
bool m_lockFileEnabled;
|
||||||
|
std::string m_lockFileName;
|
||||||
|
CMobileGPS* m_mobileGPS;
|
||||||
|
CRemoteControl* m_remoteControl;
|
||||||
|
bool m_fixedMode;
|
||||||
|
|
||||||
void readParams();
|
void readParams();
|
||||||
bool createModem();
|
bool createModem();
|
||||||
|
bool createDStarNetwork();
|
||||||
bool createDMRNetwork();
|
bool createDMRNetwork();
|
||||||
void createDisplay();
|
bool createYSFNetwork();
|
||||||
|
bool createP25Network();
|
||||||
|
bool createNXDNNetwork();
|
||||||
|
bool createPOCSAGNetwork();
|
||||||
|
|
||||||
|
void remoteControl();
|
||||||
|
void processModeCommand(unsigned char mode, unsigned int timeout);
|
||||||
|
void processEnableCommand(bool& mode, bool enabled);
|
||||||
|
|
||||||
|
void setMode(unsigned char mode);
|
||||||
|
|
||||||
|
void createLockFile(const char* mode) const;
|
||||||
|
void removeLockFile() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 14
|
# Visual Studio 15
|
||||||
VisualStudioVersion = 14.0.24720.0
|
VisualStudioVersion = 15.0.28307.271
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MMDVMHost", "MMDVMHost.vcxproj", "{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MMDVMHost", "MMDVMHost.vcxproj", "{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RemoteCommand", "RemoteCommand.vcxproj", "{5A61AB93-58BB-413A-BBD9-A26284CB37AE}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|x64 = Debug|x64
|
Debug|x64 = Debug|x64
|
||||||
|
@ -21,8 +23,19 @@ Global
|
||||||
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Release|x64.Build.0 = 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.ActiveCfg = Release|Win32
|
||||||
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Release|x86.Build.0 = Release|Win32
|
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Release|x86.Build.0 = Release|Win32
|
||||||
|
{5A61AB93-58BB-413A-BBD9-A26284CB37AE}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{5A61AB93-58BB-413A-BBD9-A26284CB37AE}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{5A61AB93-58BB-413A-BBD9-A26284CB37AE}.Debug|x86.ActiveCfg = Debug|Win32
|
||||||
|
{5A61AB93-58BB-413A-BBD9-A26284CB37AE}.Debug|x86.Build.0 = Debug|Win32
|
||||||
|
{5A61AB93-58BB-413A-BBD9-A26284CB37AE}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{5A61AB93-58BB-413A-BBD9-A26284CB37AE}.Release|x64.Build.0 = Release|x64
|
||||||
|
{5A61AB93-58BB-413A-BBD9-A26284CB37AE}.Release|x86.ActiveCfg = Release|Win32
|
||||||
|
{5A61AB93-58BB-413A-BBD9-A26284CB37AE}.Release|x86.Build.0 = Release|Win32
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {4FE84D69-7345-440E-8E0A-0CC1C84477F8}
|
||||||
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<ItemGroup Label="ProjectConfigurations">
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
<ProjectConfiguration Include="Debug|Win32">
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
<Configuration>Debug</Configuration>
|
<Configuration>Debug</Configuration>
|
||||||
|
@ -22,32 +22,32 @@
|
||||||
<ProjectGuid>{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}</ProjectGuid>
|
<ProjectGuid>{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}</ProjectGuid>
|
||||||
<Keyword>Win32Proj</Keyword>
|
<Keyword>Win32Proj</Keyword>
|
||||||
<RootNamespace>MMDVMHost</RootNamespace>
|
<RootNamespace>MMDVMHost</RootNamespace>
|
||||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
<PlatformToolset>v140</PlatformToolset>
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
<PlatformToolset>v140</PlatformToolset>
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
<UseDebugLibraries>true</UseDebugLibraries>
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
<PlatformToolset>v140</PlatformToolset>
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
<ConfigurationType>Application</ConfigurationType>
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
<UseDebugLibraries>false</UseDebugLibraries>
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
<PlatformToolset>v140</PlatformToolset>
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
<CharacterSet>Unicode</CharacterSet>
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -108,6 +108,12 @@
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<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>
|
<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>
|
</Link>
|
||||||
|
<PreBuildEvent>
|
||||||
|
<Command>"$(ProjectDir)prebuild.cmd" $(ProjectDir)</Command>
|
||||||
|
</PreBuildEvent>
|
||||||
|
<PreBuildEvent>
|
||||||
|
<Message>prebuild.cmd generates GitVersion.h from git refs heads master</Message>
|
||||||
|
</PreBuildEvent>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
|
@ -147,83 +153,194 @@
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="AMBEFEC.h" />
|
<ClInclude Include="AMBEFEC.h" />
|
||||||
|
<ClInclude Include="BCH.h" />
|
||||||
<ClInclude Include="BPTC19696.h" />
|
<ClInclude Include="BPTC19696.h" />
|
||||||
|
<ClInclude Include="CASTInfo.h" />
|
||||||
<ClInclude Include="Conf.h" />
|
<ClInclude Include="Conf.h" />
|
||||||
<ClInclude Include="CRC.h" />
|
<ClInclude Include="CRC.h" />
|
||||||
<ClInclude Include="CSBK.h" />
|
|
||||||
<ClInclude Include="Defines.h" />
|
<ClInclude Include="Defines.h" />
|
||||||
<ClInclude Include="Display.h" />
|
<ClInclude Include="Display.h" />
|
||||||
|
<ClInclude Include="DMRAccessControl.h" />
|
||||||
<ClInclude Include="DMRControl.h" />
|
<ClInclude Include="DMRControl.h" />
|
||||||
|
<ClInclude Include="DMRCSBK.h" />
|
||||||
<ClInclude Include="DMRData.h" />
|
<ClInclude Include="DMRData.h" />
|
||||||
|
<ClInclude Include="DMRDataHeader.h" />
|
||||||
<ClInclude Include="DMRDefines.h" />
|
<ClInclude Include="DMRDefines.h" />
|
||||||
|
<ClInclude Include="DMREMB.h" />
|
||||||
|
<ClInclude Include="DMREmbeddedData.h" />
|
||||||
|
<ClInclude Include="DMRFullLC.h" />
|
||||||
|
<ClInclude Include="DMRLC.h" />
|
||||||
|
<ClInclude Include="DMRNetwork.h" />
|
||||||
|
<ClInclude Include="DMRShortLC.h" />
|
||||||
<ClInclude Include="DMRSlot.h" />
|
<ClInclude Include="DMRSlot.h" />
|
||||||
<ClInclude Include="DMRSync.h" />
|
<ClInclude Include="DMRSlotType.h" />
|
||||||
|
<ClInclude Include="DMRTA.h" />
|
||||||
|
<ClInclude Include="DMRTrellis.h" />
|
||||||
|
<ClInclude Include="DStarControl.h" />
|
||||||
<ClInclude Include="DStarDefines.h" />
|
<ClInclude Include="DStarDefines.h" />
|
||||||
<ClInclude Include="DStarEcho.h" />
|
<ClInclude Include="DStarHeader.h" />
|
||||||
<ClInclude Include="EMB.h" />
|
<ClInclude Include="DStarNetwork.h" />
|
||||||
<ClInclude Include="EmbeddedLC.h" />
|
<ClInclude Include="DStarSlowData.h" />
|
||||||
<ClInclude Include="FullLC.h" />
|
|
||||||
<ClInclude Include="Golay2087.h" />
|
<ClInclude Include="Golay2087.h" />
|
||||||
<ClInclude Include="Golay24128.h" />
|
<ClInclude Include="Golay24128.h" />
|
||||||
<ClInclude Include="Hamming.h" />
|
<ClInclude Include="Hamming.h" />
|
||||||
<ClInclude Include="HomebrewDMRIPSC.h" />
|
<ClInclude Include="DMRLookup.h" />
|
||||||
<ClInclude Include="LC.h" />
|
<ClInclude Include="I2CController.h" />
|
||||||
|
<ClInclude Include="LCDproc.h" />
|
||||||
<ClInclude Include="Log.h" />
|
<ClInclude Include="Log.h" />
|
||||||
<ClInclude Include="MMDVMHost.h" />
|
<ClInclude Include="MMDVMHost.h" />
|
||||||
|
<ClInclude Include="MobileGPS.h" />
|
||||||
<ClInclude Include="Modem.h" />
|
<ClInclude Include="Modem.h" />
|
||||||
|
<ClInclude Include="ModemSerialPort.h" />
|
||||||
|
<ClInclude Include="Mutex.h" />
|
||||||
|
<ClInclude Include="NetworkInfo.h" />
|
||||||
|
<ClInclude Include="Nextion.h" />
|
||||||
<ClInclude Include="NullDisplay.h" />
|
<ClInclude Include="NullDisplay.h" />
|
||||||
|
<ClInclude Include="NullModem.h" />
|
||||||
|
<ClInclude Include="NXDNAudio.h" />
|
||||||
|
<ClInclude Include="NXDNControl.h" />
|
||||||
|
<ClInclude Include="NXDNConvolution.h" />
|
||||||
|
<ClInclude Include="NXDNCRC.h" />
|
||||||
|
<ClInclude Include="NXDNDefines.h" />
|
||||||
|
<ClInclude Include="NXDNFACCH1.h" />
|
||||||
|
<ClInclude Include="NXDNIcomNetwork.h" />
|
||||||
|
<ClInclude Include="NXDNKenwoodNetwork.h" />
|
||||||
|
<ClInclude Include="NXDNLayer3.h" />
|
||||||
|
<ClInclude Include="NXDNLICH.h" />
|
||||||
|
<ClInclude Include="NXDNLookup.h" />
|
||||||
|
<ClInclude Include="NXDNNetwork.h" />
|
||||||
|
<ClInclude Include="NXDNUDCH.h" />
|
||||||
|
<ClInclude Include="P25Audio.h" />
|
||||||
|
<ClInclude Include="P25Control.h" />
|
||||||
|
<ClInclude Include="P25Defines.h" />
|
||||||
|
<ClInclude Include="P25Data.h" />
|
||||||
|
<ClInclude Include="P25LowSpeedData.h" />
|
||||||
|
<ClInclude Include="P25Network.h" />
|
||||||
|
<ClInclude Include="P25NID.h" />
|
||||||
|
<ClInclude Include="P25Trellis.h" />
|
||||||
|
<ClInclude Include="P25Utils.h" />
|
||||||
|
<ClInclude Include="POCSAGControl.h" />
|
||||||
|
<ClInclude Include="POCSAGDefines.h" />
|
||||||
|
<ClInclude Include="POCSAGNetwork.h" />
|
||||||
<ClInclude Include="QR1676.h" />
|
<ClInclude Include="QR1676.h" />
|
||||||
|
<ClInclude Include="RemoteControl.h" />
|
||||||
<ClInclude Include="RingBuffer.h" />
|
<ClInclude Include="RingBuffer.h" />
|
||||||
<ClInclude Include="RS129.h" />
|
<ClInclude Include="RS129.h" />
|
||||||
|
<ClInclude Include="RS241213.h" />
|
||||||
|
<ClInclude Include="RSSIInterpolator.h" />
|
||||||
|
<ClInclude Include="NXDNSACCH.h" />
|
||||||
<ClInclude Include="SerialController.h" />
|
<ClInclude Include="SerialController.h" />
|
||||||
|
<ClInclude Include="SerialPort.h" />
|
||||||
<ClInclude Include="SHA256.h" />
|
<ClInclude Include="SHA256.h" />
|
||||||
<ClInclude Include="ShortLC.h" />
|
|
||||||
<ClInclude Include="SlotType.h" />
|
|
||||||
<ClInclude Include="StopWatch.h" />
|
<ClInclude Include="StopWatch.h" />
|
||||||
|
<ClInclude Include="Sync.h" />
|
||||||
<ClInclude Include="TFTSerial.h" />
|
<ClInclude Include="TFTSerial.h" />
|
||||||
|
<ClInclude Include="TFTSurenoo.h" />
|
||||||
|
<ClInclude Include="Thread.h" />
|
||||||
<ClInclude Include="Timer.h" />
|
<ClInclude Include="Timer.h" />
|
||||||
<ClInclude Include="UDPSocket.h" />
|
<ClInclude Include="UDPSocket.h" />
|
||||||
|
<ClInclude Include="UMP.h" />
|
||||||
|
<ClInclude Include="UserDB.h" />
|
||||||
|
<ClInclude Include="UserDBentry.h" />
|
||||||
<ClInclude Include="Utils.h" />
|
<ClInclude Include="Utils.h" />
|
||||||
<ClInclude Include="Version.h" />
|
<ClInclude Include="Version.h" />
|
||||||
|
<ClInclude Include="YSFControl.h" />
|
||||||
|
<ClInclude Include="YSFConvolution.h" />
|
||||||
<ClInclude Include="YSFDefines.h" />
|
<ClInclude Include="YSFDefines.h" />
|
||||||
<ClInclude Include="YSFEcho.h" />
|
<ClInclude Include="YSFFICH.h" />
|
||||||
|
<ClInclude Include="YSFNetwork.h" />
|
||||||
|
<ClInclude Include="YSFPayload.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="AMBEFEC.cpp" />
|
<ClCompile Include="AMBEFEC.cpp" />
|
||||||
|
<ClCompile Include="BCH.cpp" />
|
||||||
<ClCompile Include="BPTC19696.cpp" />
|
<ClCompile Include="BPTC19696.cpp" />
|
||||||
|
<ClCompile Include="CASTInfo.cpp" />
|
||||||
<ClCompile Include="Conf.cpp" />
|
<ClCompile Include="Conf.cpp" />
|
||||||
<ClCompile Include="CRC.cpp" />
|
<ClCompile Include="CRC.cpp" />
|
||||||
<ClCompile Include="CSBK.cpp" />
|
|
||||||
<ClCompile Include="Display.cpp" />
|
<ClCompile Include="Display.cpp" />
|
||||||
|
<ClCompile Include="DMRAccessControl.cpp" />
|
||||||
<ClCompile Include="DMRControl.cpp" />
|
<ClCompile Include="DMRControl.cpp" />
|
||||||
|
<ClCompile Include="DMRCSBK.cpp" />
|
||||||
<ClCompile Include="DMRData.cpp" />
|
<ClCompile Include="DMRData.cpp" />
|
||||||
|
<ClCompile Include="DMRDataHeader.cpp" />
|
||||||
|
<ClCompile Include="DMREMB.cpp" />
|
||||||
|
<ClCompile Include="DMREmbeddedData.cpp" />
|
||||||
|
<ClCompile Include="DMRFullLC.cpp" />
|
||||||
|
<ClCompile Include="DMRLC.cpp" />
|
||||||
|
<ClCompile Include="DMRLookup.cpp" />
|
||||||
|
<ClCompile Include="DMRNetwork.cpp" />
|
||||||
|
<ClCompile Include="DMRShortLC.cpp" />
|
||||||
<ClCompile Include="DMRSlot.cpp" />
|
<ClCompile Include="DMRSlot.cpp" />
|
||||||
<ClCompile Include="DMRSync.cpp" />
|
<ClCompile Include="DMRSlotType.cpp" />
|
||||||
<ClCompile Include="DStarEcho.cpp" />
|
<ClCompile Include="DMRTA.cpp" />
|
||||||
<ClCompile Include="EMB.cpp" />
|
<ClCompile Include="DMRTrellis.cpp" />
|
||||||
<ClCompile Include="EmbeddedLC.cpp" />
|
<ClCompile Include="DStarControl.cpp" />
|
||||||
<ClCompile Include="FullLC.cpp" />
|
<ClCompile Include="DStarHeader.cpp" />
|
||||||
|
<ClCompile Include="DStarNetwork.cpp" />
|
||||||
|
<ClCompile Include="DStarSlowData.cpp" />
|
||||||
<ClCompile Include="Golay2087.cpp" />
|
<ClCompile Include="Golay2087.cpp" />
|
||||||
<ClCompile Include="Golay24128.cpp" />
|
<ClCompile Include="Golay24128.cpp" />
|
||||||
<ClCompile Include="Hamming.cpp" />
|
<ClCompile Include="Hamming.cpp" />
|
||||||
<ClCompile Include="HomebrewDMRIPSC.cpp" />
|
<ClCompile Include="I2CController.cpp" />
|
||||||
<ClCompile Include="LC.cpp" />
|
<ClCompile Include="LCDproc.cpp" />
|
||||||
<ClCompile Include="Log.cpp" />
|
<ClCompile Include="Log.cpp" />
|
||||||
<ClCompile Include="MMDVMHost.cpp" />
|
<ClCompile Include="MMDVMHost.cpp" />
|
||||||
|
<ClCompile Include="MobileGPS.cpp" />
|
||||||
<ClCompile Include="Modem.cpp" />
|
<ClCompile Include="Modem.cpp" />
|
||||||
|
<ClCompile Include="ModemSerialPort.cpp" />
|
||||||
|
<ClCompile Include="Mutex.cpp" />
|
||||||
|
<ClCompile Include="NetworkInfo.cpp" />
|
||||||
|
<ClCompile Include="Nextion.cpp" />
|
||||||
<ClCompile Include="NullDisplay.cpp" />
|
<ClCompile Include="NullDisplay.cpp" />
|
||||||
|
<ClCompile Include="NullModem.cpp" />
|
||||||
|
<ClCompile Include="NXDNAudio.cpp" />
|
||||||
|
<ClCompile Include="NXDNControl.cpp" />
|
||||||
|
<ClCompile Include="NXDNConvolution.cpp" />
|
||||||
|
<ClCompile Include="NXDNCRC.cpp" />
|
||||||
|
<ClCompile Include="NXDNFACCH1.cpp" />
|
||||||
|
<ClCompile Include="NXDNIcomNetwork.cpp" />
|
||||||
|
<ClCompile Include="NXDNKenwoodNetwork.cpp" />
|
||||||
|
<ClCompile Include="NXDNLayer3.cpp" />
|
||||||
|
<ClCompile Include="NXDNLICH.cpp" />
|
||||||
|
<ClCompile Include="NXDNLookup.cpp" />
|
||||||
|
<ClCompile Include="NXDNNetwork.cpp" />
|
||||||
|
<ClCompile Include="NXDNSACCH.cpp" />
|
||||||
|
<ClCompile Include="NXDNUDCH.cpp" />
|
||||||
|
<ClCompile Include="P25Audio.cpp" />
|
||||||
|
<ClCompile Include="P25Control.cpp" />
|
||||||
|
<ClCompile Include="P25Data.cpp" />
|
||||||
|
<ClCompile Include="P25LowSpeedData.cpp" />
|
||||||
|
<ClCompile Include="P25Network.cpp" />
|
||||||
|
<ClCompile Include="P25NID.cpp" />
|
||||||
|
<ClCompile Include="P25Trellis.cpp" />
|
||||||
|
<ClCompile Include="P25Utils.cpp" />
|
||||||
|
<ClCompile Include="POCSAGControl.cpp" />
|
||||||
|
<ClCompile Include="POCSAGNetwork.cpp" />
|
||||||
<ClCompile Include="QR1676.cpp" />
|
<ClCompile Include="QR1676.cpp" />
|
||||||
|
<ClCompile Include="RemoteControl.cpp" />
|
||||||
<ClCompile Include="RS129.cpp" />
|
<ClCompile Include="RS129.cpp" />
|
||||||
|
<ClCompile Include="RS241213.cpp" />
|
||||||
|
<ClCompile Include="RSSIInterpolator.cpp" />
|
||||||
<ClCompile Include="SerialController.cpp" />
|
<ClCompile Include="SerialController.cpp" />
|
||||||
|
<ClCompile Include="SerialPort.cpp" />
|
||||||
<ClCompile Include="SHA256.cpp" />
|
<ClCompile Include="SHA256.cpp" />
|
||||||
<ClCompile Include="ShortLC.cpp" />
|
|
||||||
<ClCompile Include="SlotType.cpp" />
|
|
||||||
<ClCompile Include="StopWatch.cpp" />
|
<ClCompile Include="StopWatch.cpp" />
|
||||||
|
<ClCompile Include="Sync.cpp" />
|
||||||
<ClCompile Include="TFTSerial.cpp" />
|
<ClCompile Include="TFTSerial.cpp" />
|
||||||
|
<ClCompile Include="TFTSurenoo.cpp" />
|
||||||
|
<ClCompile Include="Thread.cpp" />
|
||||||
<ClCompile Include="Timer.cpp" />
|
<ClCompile Include="Timer.cpp" />
|
||||||
<ClCompile Include="UDPSocket.cpp" />
|
<ClCompile Include="UDPSocket.cpp" />
|
||||||
|
<ClCompile Include="UMP.cpp" />
|
||||||
|
<ClCompile Include="UserDB.cpp" />
|
||||||
|
<ClCompile Include="UserDBentry.cpp" />
|
||||||
<ClCompile Include="Utils.cpp" />
|
<ClCompile Include="Utils.cpp" />
|
||||||
<ClCompile Include="YSFEcho.cpp" />
|
<ClCompile Include="YSFNetwork.cpp" />
|
||||||
|
<ClCompile Include="YSFPayload.cpp" />
|
||||||
|
<ClCompile Include="YSFControl.cpp" />
|
||||||
|
<ClCompile Include="YSFConvolution.cpp" />
|
||||||
|
<ClCompile Include="YSFFICH.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
|