Progress on P25 data.
This commit is contained in:
parent
c8c9332b04
commit
4665d590f8
|
@ -200,6 +200,7 @@
|
||||||
<ClInclude Include="P25LowSpeedData.h" />
|
<ClInclude Include="P25LowSpeedData.h" />
|
||||||
<ClInclude Include="P25Network.h" />
|
<ClInclude Include="P25Network.h" />
|
||||||
<ClInclude Include="P25NID.h" />
|
<ClInclude Include="P25NID.h" />
|
||||||
|
<ClInclude Include="P25Trellis.h" />
|
||||||
<ClInclude Include="P25Utils.h" />
|
<ClInclude Include="P25Utils.h" />
|
||||||
<ClInclude Include="QR1676.h" />
|
<ClInclude Include="QR1676.h" />
|
||||||
<ClInclude Include="RingBuffer.h" />
|
<ClInclude Include="RingBuffer.h" />
|
||||||
|
@ -270,6 +271,7 @@
|
||||||
<ClCompile Include="P25LowSpeedData.cpp" />
|
<ClCompile Include="P25LowSpeedData.cpp" />
|
||||||
<ClCompile Include="P25Network.cpp" />
|
<ClCompile Include="P25Network.cpp" />
|
||||||
<ClCompile Include="P25NID.cpp" />
|
<ClCompile Include="P25NID.cpp" />
|
||||||
|
<ClCompile Include="P25Trellis.cpp" />
|
||||||
<ClCompile Include="P25Utils.cpp" />
|
<ClCompile Include="P25Utils.cpp" />
|
||||||
<ClCompile Include="QR1676.cpp" />
|
<ClCompile Include="QR1676.cpp" />
|
||||||
<ClCompile Include="RS129.cpp" />
|
<ClCompile Include="RS129.cpp" />
|
||||||
|
|
|
@ -227,6 +227,9 @@
|
||||||
<ClInclude Include="JitterBuffer.h">
|
<ClInclude Include="JitterBuffer.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="P25Trellis.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="BPTC19696.cpp">
|
<ClCompile Include="BPTC19696.cpp">
|
||||||
|
@ -424,5 +427,8 @@
|
||||||
<ClCompile Include="JitterBuffer.cpp">
|
<ClCompile Include="JitterBuffer.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="P25Trellis.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
|
@ -67,6 +67,10 @@ m_netLDU1(NULL),
|
||||||
m_netLDU2(NULL),
|
m_netLDU2(NULL),
|
||||||
m_lastIMBE(NULL),
|
m_lastIMBE(NULL),
|
||||||
m_rfLDU(NULL),
|
m_rfLDU(NULL),
|
||||||
|
m_rfPDURaw(NULL),
|
||||||
|
m_rfPDUCooked(NULL),
|
||||||
|
m_rfPDUCount(0U),
|
||||||
|
m_rfPDUBits(0U),
|
||||||
m_rssiMapper(rssiMapper),
|
m_rssiMapper(rssiMapper),
|
||||||
m_rssi(0U),
|
m_rssi(0U),
|
||||||
m_maxRSSI(0U),
|
m_maxRSSI(0U),
|
||||||
|
@ -90,6 +94,12 @@ m_fp(NULL)
|
||||||
|
|
||||||
m_rfLDU = new unsigned char[P25_LDU_FRAME_LENGTH_BYTES];
|
m_rfLDU = new unsigned char[P25_LDU_FRAME_LENGTH_BYTES];
|
||||||
::memset(m_rfLDU, 0x00U, P25_LDU_FRAME_LENGTH_BYTES);
|
::memset(m_rfLDU, 0x00U, P25_LDU_FRAME_LENGTH_BYTES);
|
||||||
|
|
||||||
|
m_rfPDURaw = new unsigned char[P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES];
|
||||||
|
::memset(m_rfPDURaw, 0x00U, P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES);
|
||||||
|
|
||||||
|
m_rfPDUCooked = new unsigned char[P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES];
|
||||||
|
::memset(m_rfPDUCooked, 0x00U, P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
CP25Control::~CP25Control()
|
CP25Control::~CP25Control()
|
||||||
|
@ -98,6 +108,8 @@ CP25Control::~CP25Control()
|
||||||
delete[] m_netLDU2;
|
delete[] m_netLDU2;
|
||||||
delete[] m_lastIMBE;
|
delete[] m_lastIMBE;
|
||||||
delete[] m_rfLDU;
|
delete[] m_rfLDU;
|
||||||
|
delete[] m_rfPDURaw;
|
||||||
|
delete[] m_rfPDUCooked;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CP25Control::writeModem(unsigned char* data, unsigned int len)
|
bool CP25Control::writeModem(unsigned char* data, unsigned int len)
|
||||||
|
@ -126,6 +138,19 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data[0U] == TAG_LOST && m_rfState == RS_RF_DATA) {
|
||||||
|
if (m_netState == RS_NET_IDLE)
|
||||||
|
m_display->clearP25();
|
||||||
|
|
||||||
|
m_rfState = RS_RF_LISTENING;
|
||||||
|
m_rfPDUCount = 0U;
|
||||||
|
m_rfPDUBits = 0U;
|
||||||
|
#if defined(DUMP_P25)
|
||||||
|
closeFile();
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (data[0U] == TAG_LOST) {
|
if (data[0U] == TAG_LOST) {
|
||||||
m_rfState = RS_RF_LISTENING;
|
m_rfState = RS_RF_LISTENING;
|
||||||
return false;
|
return false;
|
||||||
|
@ -362,9 +387,29 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (duid == P25_DUID_PDU) {
|
} else if (duid == P25_DUID_PDU) {
|
||||||
|
if (m_rfState != RS_RF_DATA) {
|
||||||
|
m_rfPDUCount = 0U;
|
||||||
|
m_rfPDUBits = 0U;
|
||||||
|
m_rfState = RS_RF_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int start = m_rfPDUCount * P25_LDU_FRAME_LENGTH_BITS;
|
||||||
|
|
||||||
|
unsigned char buffer[P25_LDU_FRAME_LENGTH_BYTES];
|
||||||
|
unsigned int bits = CP25Utils::decode(data + 2U, buffer, start, start + P25_LDU_FRAME_LENGTH_BITS);
|
||||||
|
|
||||||
|
for (unsigned int i = 0U; i < bits; i++, m_rfPDUBits++) {
|
||||||
|
bool b = READ_BIT(buffer, i);
|
||||||
|
WRITE_BIT(m_rfPDUCooked, m_rfPDUBits, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
::memcpy(m_rfPDURaw + m_rfPDUCount * P25_LDU_FRAME_LENGTH_BYTES, data + 2U, P25_LDU_FRAME_LENGTH_BYTES);
|
||||||
|
m_rfPDUCount++;
|
||||||
|
|
||||||
|
LogMessage("P25, received %u (%u) bits in %u LDUs", m_rfPDUBits, m_rfPDUBits - P25_SYNC_BITS_LENGTH - P25_NID_LENGTH_BITS, m_rfPDUCount);
|
||||||
|
|
||||||
LogMessage("P25, PDU received");
|
LogMessage("P25, PDU received");
|
||||||
CUtils::dump("P25, PDU data", data + 2U, P25_LDU_FRAME_LENGTH_BYTES);
|
CUtils::dump("P25, PDU data", data + 2U, P25_LDU_FRAME_LENGTH_BYTES);
|
||||||
m_rfState = RS_RF_DATA;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2016,2017 by Jonathan Naylor G4KLX
|
* Copyright (C) 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
|
||||||
|
@ -77,6 +77,10 @@ private:
|
||||||
unsigned char* m_netLDU2;
|
unsigned char* m_netLDU2;
|
||||||
unsigned char* m_lastIMBE;
|
unsigned char* m_lastIMBE;
|
||||||
unsigned char* m_rfLDU;
|
unsigned char* m_rfLDU;
|
||||||
|
unsigned char* m_rfPDURaw;
|
||||||
|
unsigned char* m_rfPDUCooked;
|
||||||
|
unsigned int m_rfPDUCount;
|
||||||
|
unsigned int m_rfPDUBits;
|
||||||
CRSSIInterpolator* m_rssiMapper;
|
CRSSIInterpolator* m_rssiMapper;
|
||||||
unsigned char m_rssi;
|
unsigned char m_rssi;
|
||||||
unsigned char m_maxRSSI;
|
unsigned char m_maxRSSI;
|
||||||
|
|
|
@ -38,6 +38,9 @@ const unsigned int P25_NID_LENGTH_BITS = P25_NID_LENGTH_BYTES * 8U;
|
||||||
|
|
||||||
const unsigned char P25_SYNC_BYTES[] = {0x55U, 0x75U, 0xF5U, 0xFFU, 0x77U, 0xFFU};
|
const unsigned char P25_SYNC_BYTES[] = {0x55U, 0x75U, 0xF5U, 0xFFU, 0x77U, 0xFFU};
|
||||||
const unsigned char P25_SYNC_BYTES_LENGTH = 6U;
|
const unsigned char P25_SYNC_BYTES_LENGTH = 6U;
|
||||||
|
const unsigned int P25_SYNC_BITS_LENGTH = P25_SYNC_BYTES_LENGTH * 8U;
|
||||||
|
|
||||||
|
const unsigned int P25_MAX_PDU_COUNT = 10U;
|
||||||
|
|
||||||
const unsigned int P25_MI_LENGTH_BYTES = 9U;
|
const unsigned int P25_MI_LENGTH_BYTES = 9U;
|
||||||
|
|
||||||
|
|
529
P25Trellis.cpp
Normal file
529
P25Trellis.cpp
Normal file
|
@ -0,0 +1,529 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016,2018 by Jonathan Naylor, G4KLX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; 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 "P25Trellis.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_34[] = {
|
||||||
|
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 ENCODE_TABLE_12[] = {
|
||||||
|
0U, 15U, 12U, 3U,
|
||||||
|
4U, 11U, 8U, 7U,
|
||||||
|
13U, 2U, 1U, 14U,
|
||||||
|
9U, 6U, 5U, 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])
|
||||||
|
|
||||||
|
CP25Trellis::CP25Trellis()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CP25Trellis::~CP25Trellis()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CP25Trellis::decode34(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 = checkCode34(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 = fixCode34(points, failPos, payload);
|
||||||
|
if (ret)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (failPos == 0U)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Backtrack one place for a last go
|
||||||
|
return fixCode34(savePoints, failPos - 1U, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CP25Trellis::encode34(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_34[state * 8U + tribit];
|
||||||
|
|
||||||
|
state = tribit;
|
||||||
|
}
|
||||||
|
|
||||||
|
signed char dibits[98U];
|
||||||
|
pointsToDibits(points, dibits);
|
||||||
|
|
||||||
|
interleave(dibits, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CP25Trellis::decode12(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 bits[49U];
|
||||||
|
unsigned int failPos = checkCode12(points, bits);
|
||||||
|
if (failPos == 999U) {
|
||||||
|
dibitsToBits(bits, payload);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char savePoints[49U];
|
||||||
|
for (unsigned int i = 0U; i < 49U; i++)
|
||||||
|
savePoints[i] = points[i];
|
||||||
|
|
||||||
|
bool ret = fixCode12(points, failPos, payload);
|
||||||
|
if (ret)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (failPos == 0U)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Backtrack one place for a last go
|
||||||
|
return fixCode12(savePoints, failPos - 1U, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CP25Trellis::encode12(const unsigned char* payload, unsigned char* data)
|
||||||
|
{
|
||||||
|
assert(payload != NULL);
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
|
unsigned char bits[49U];
|
||||||
|
bitsToDibits(payload, bits);
|
||||||
|
|
||||||
|
unsigned char points[49U];
|
||||||
|
unsigned char state = 0U;
|
||||||
|
|
||||||
|
for (unsigned int i = 0U; i < 49U; i++) {
|
||||||
|
unsigned char bit = bits[i];
|
||||||
|
|
||||||
|
points[i] = ENCODE_TABLE_12[state * 4U + bit];
|
||||||
|
|
||||||
|
state = bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
signed char dibits[98U];
|
||||||
|
pointsToDibits(points, dibits);
|
||||||
|
|
||||||
|
interleave(dibits, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CP25Trellis::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 CP25Trellis::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 CP25Trellis::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 CP25Trellis::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 CP25Trellis::bitsToTribits(const unsigned char* payload, unsigned char* tribits) const
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0U; i < 48U; i++) {
|
||||||
|
unsigned int n = 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 CP25Trellis::bitsToDibits(const unsigned char* payload, unsigned char* dibits) const
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0U; i < 48U; i++) {
|
||||||
|
unsigned int n = i * 2U;
|
||||||
|
|
||||||
|
bool b1 = READ_BIT(payload, n) != 0x00U;
|
||||||
|
n++;
|
||||||
|
bool b2 = READ_BIT(payload, n) != 0x00U;
|
||||||
|
|
||||||
|
unsigned char dibit = 0U;
|
||||||
|
dibit |= b1 ? 2U : 0U;
|
||||||
|
dibit |= b2 ? 1U : 0U;
|
||||||
|
|
||||||
|
dibits[i] = dibit;
|
||||||
|
}
|
||||||
|
|
||||||
|
dibits[48U] = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CP25Trellis::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 = i * 3U;
|
||||||
|
|
||||||
|
WRITE_BIT(payload, n, b1);
|
||||||
|
n++;
|
||||||
|
WRITE_BIT(payload, n, b2);
|
||||||
|
n++;
|
||||||
|
WRITE_BIT(payload, n, b3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CP25Trellis::dibitsToBits(const unsigned char* dibits, unsigned char* payload) const
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0U; i < 48U; i++) {
|
||||||
|
unsigned char dibit = dibits[i];
|
||||||
|
|
||||||
|
bool b1 = (dibit & 0x02U) == 0x02U;
|
||||||
|
bool b2 = (dibit & 0x01U) == 0x01U;
|
||||||
|
|
||||||
|
unsigned int n = i * 2U;
|
||||||
|
|
||||||
|
WRITE_BIT(payload, n, b1);
|
||||||
|
n++;
|
||||||
|
WRITE_BIT(payload, n, b2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CP25Trellis::fixCode34(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 = checkCode34(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 CP25Trellis::checkCode34(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_34[state * 8U + j]) {
|
||||||
|
tribits[i] = j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tribits[i] == 9U)
|
||||||
|
return i;
|
||||||
|
|
||||||
|
state = tribits[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tribits[48U] != 0U)
|
||||||
|
return 48U;
|
||||||
|
|
||||||
|
return 999U;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool CP25Trellis::fixCode12(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 < 4U; i++) {
|
||||||
|
points[failPos] = i;
|
||||||
|
|
||||||
|
unsigned char dibits[49U];
|
||||||
|
unsigned int pos = checkCode12(points, dibits);
|
||||||
|
if (pos == 999U) {
|
||||||
|
dibitsToBits(dibits, payload);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos > bestPos) {
|
||||||
|
bestPos = pos;
|
||||||
|
bestVal = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
points[failPos] = bestVal;
|
||||||
|
failPos = bestPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CP25Trellis::checkCode12(const unsigned char* points, unsigned char* dibits) const
|
||||||
|
{
|
||||||
|
unsigned char state = 0U;
|
||||||
|
|
||||||
|
for (unsigned int i = 0U; i < 49U; i++) {
|
||||||
|
dibits[i] = 5U;
|
||||||
|
|
||||||
|
for (unsigned int j = 0U; j < 4U; j++) {
|
||||||
|
if (points[i] == ENCODE_TABLE_12[state * 4U + j]) {
|
||||||
|
dibits[i] = j;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dibits[i] == 5U)
|
||||||
|
return i;
|
||||||
|
|
||||||
|
state = dibits[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dibits[48U] != 0U)
|
||||||
|
return 48U;
|
||||||
|
|
||||||
|
return 999U;
|
||||||
|
}
|
43
P25Trellis.h
Normal file
43
P25Trellis.h
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016,2018 by Jonathan Naylor, G4KLX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; 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 P25Trellis_H
|
||||||
|
#define P25Trellis_H
|
||||||
|
|
||||||
|
class CP25Trellis {
|
||||||
|
public:
|
||||||
|
CP25Trellis();
|
||||||
|
~CP25Trellis();
|
||||||
|
|
||||||
|
bool decode34(const unsigned char* data, unsigned char* payload);
|
||||||
|
void encode34(const unsigned char* payload, unsigned char* data);
|
||||||
|
|
||||||
|
bool decode12(const unsigned char* data, unsigned char* payload);
|
||||||
|
void encode12(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 bitsToDibits(const unsigned char* payload, unsigned char* dibits) const;
|
||||||
|
void tribitsToBits(const unsigned char* tribits, unsigned char* payload) const;
|
||||||
|
void dibitsToBits(const unsigned char* dibits, unsigned char* payload) const;
|
||||||
|
bool fixCode34(unsigned char* points, unsigned int failPos, unsigned char* payload) const;
|
||||||
|
unsigned int checkCode34(const unsigned char* points, unsigned char* tribits) const;
|
||||||
|
bool fixCode12(unsigned char* points, unsigned int failPos, unsigned char* payload) const;
|
||||||
|
unsigned int checkCode12(const unsigned char* points, unsigned char* dibits) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
10
P25Utils.cpp
10
P25Utils.cpp
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2016 by Jonathan Naylor G4KLX
|
* Copyright (C) 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
|
||||||
|
@ -27,7 +27,7 @@ const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04
|
||||||
#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])
|
||||||
|
|
||||||
void CP25Utils::decode(const unsigned char* in, unsigned char* out, unsigned int start, unsigned int stop)
|
unsigned int CP25Utils::decode(const unsigned char* in, unsigned char* out, unsigned int start, unsigned int stop)
|
||||||
{
|
{
|
||||||
assert(in != NULL);
|
assert(in != NULL);
|
||||||
assert(out != NULL);
|
assert(out != NULL);
|
||||||
|
@ -53,9 +53,11 @@ void CP25Utils::decode(const unsigned char* in, unsigned char* out, unsigned int
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CP25Utils::encode(const unsigned char* in, unsigned char* out, unsigned int start, unsigned int stop)
|
unsigned int CP25Utils::encode(const unsigned char* in, unsigned char* out, unsigned int start, unsigned int stop)
|
||||||
{
|
{
|
||||||
assert(in != NULL);
|
assert(in != NULL);
|
||||||
assert(out != NULL);
|
assert(out != NULL);
|
||||||
|
@ -81,6 +83,8 @@ void CP25Utils::encode(const unsigned char* in, unsigned char* out, unsigned int
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int CP25Utils::compare(const unsigned char* data1, const unsigned char* data2, unsigned int length)
|
unsigned int CP25Utils::compare(const unsigned char* data1, const unsigned char* data2, unsigned int length)
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2016 by Jonathan Naylor G4KLX
|
* Copyright (C) 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
|
||||||
|
@ -21,9 +21,9 @@
|
||||||
|
|
||||||
class CP25Utils {
|
class CP25Utils {
|
||||||
public:
|
public:
|
||||||
static void encode(const unsigned char* in, unsigned char* out, unsigned int start, unsigned int stop);
|
static unsigned int encode(const unsigned char* in, unsigned char* out, unsigned int start, unsigned int stop);
|
||||||
|
|
||||||
static void decode(const unsigned char* in, unsigned char* out, unsigned int start, unsigned int stop);
|
static unsigned int decode(const unsigned char* in, unsigned char* out, unsigned int start, unsigned int stop);
|
||||||
|
|
||||||
static unsigned int compare(const unsigned char* data1, const unsigned char* data2, unsigned int length);
|
static unsigned int compare(const unsigned char* data1, const unsigned char* data2, unsigned int length);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue