Skip to content

Commit

Permalink
Fix P25 data reception, regeneration, and transmission.
Browse files Browse the repository at this point in the history
  • Loading branch information
g4klx committed Jan 16, 2018
1 parent 323179d commit 082c2e1
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 43 deletions.
124 changes: 88 additions & 36 deletions P25Control.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "P25Utils.h"
#include "Utils.h"
#include "Sync.h"
#include "CRC.h"
#include "Log.h"

#include <cassert>
Expand Down Expand Up @@ -57,6 +58,7 @@ m_rfBits(0U),
m_rfErrs(0U),
m_netFrames(0U),
m_netLost(0U),
m_rfDataFrames(0U),
m_nid(nac),
m_lastDUID(P25_DUID_TERM),
m_audio(),
Expand All @@ -68,8 +70,7 @@ m_netLDU1(NULL),
m_netLDU2(NULL),
m_lastIMBE(NULL),
m_rfLDU(NULL),
m_rfPDURaw(NULL),
m_rfPDUCooked(NULL),
m_rfPDU(NULL),
m_rfPDUCount(0U),
m_rfPDUBits(0U),
m_rssiMapper(rssiMapper),
Expand All @@ -96,11 +97,8 @@ m_fp(NULL)
m_rfLDU = new unsigned char[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 + 2U];
::memset(m_rfPDURaw, 0x00U, P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES + 2U);

m_rfPDUCooked = new unsigned char[P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES + 2U];
::memset(m_rfPDUCooked, 0x00U, P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES + 2U);
m_rfPDU = new unsigned char[P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES + 2U];
::memset(m_rfPDU, 0x00U, P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES + 2U);
}

CP25Control::~CP25Control()
Expand All @@ -109,8 +107,7 @@ CP25Control::~CP25Control()
delete[] m_netLDU2;
delete[] m_lastIMBE;
delete[] m_rfLDU;
delete[] m_rfPDURaw;
delete[] m_rfPDUCooked;
delete[] m_rfPDU;
}

bool CP25Control::writeModem(unsigned char* data, unsigned int len)
Expand Down Expand Up @@ -243,7 +240,7 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len)
unsigned int dstId = m_rfData.getDstId();
std::string source = m_lookup->find(srcId);

LogMessage("P25, received RF transmission from %s to %s%u", source.c_str(), grp ? "TG " : "", dstId);
LogMessage("P25, received RF voice transmission from %s to %s%u", source.c_str(), grp ? "TG " : "", dstId);
m_display->writeP25(source.c_str(), grp, dstId, "R");

m_rfState = RS_RF_AUDIO;
Expand Down Expand Up @@ -369,9 +366,9 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len)
m_lastDUID = duid;

if (m_rssi != 0U)
LogMessage("P25, received RF end of transmission, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount);
LogMessage("P25, received RF end of voice transmission, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount);
else
LogMessage("P25, received RF end of transmission, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits));
LogMessage("P25, received RF end of voice transmission, %.1f seconds, BER: %.1f%%", float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits));

m_display->clearP25();

Expand All @@ -389,9 +386,10 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len)
}
} else if (duid == P25_DUID_PDU) {
if (m_rfState != RS_RF_DATA) {
m_rfPDUCount = 0U;
m_rfPDUBits = 0U;
m_rfState = RS_RF_DATA;
m_rfPDUCount = 0U;
m_rfPDUBits = 0U;
m_rfState = RS_RF_DATA;
m_rfDataFrames = 0U;
}

unsigned int start = m_rfPDUCount * P25_LDU_FRAME_LENGTH_BITS;
Expand All @@ -401,41 +399,95 @@ bool CP25Control::writeModem(unsigned char* data, unsigned int len)

for (unsigned int i = 0U; i < bits; i++, m_rfPDUBits++) {
bool b = READ_BIT(buffer, i);
WRITE_BIT(m_rfPDUCooked, m_rfPDUBits, b);
WRITE_BIT(m_rfPDU, m_rfPDUBits, b);
}

if (m_rfPDUCount == 0U) {
CUtils::dump("P25, PDU header raw", m_rfPDUCooked + P25_SYNC_LENGTH_BYTES + P25_NID_LENGTH_BYTES, P25_PDU_HEADER_LENGTH_BYTES * 2U);

CP25Trellis trellis;
unsigned char header[P25_PDU_HEADER_LENGTH_BYTES];
bool valid = trellis.decode12(m_rfPDUCooked + P25_SYNC_LENGTH_BITS + P25_NID_LENGTH_BITS, header);
bool valid = trellis.decode12(m_rfPDU + P25_SYNC_LENGTH_BYTES + P25_NID_LENGTH_BYTES, header);
if (valid)
CUtils::dump("P25, PDU header decoded", header, P25_PDU_HEADER_LENGTH_BYTES);
valid = CCRC::checkCCITT162(header, P25_PDU_HEADER_LENGTH_BYTES);

if (valid) {
unsigned int llId = (header[3U] << 16) + (header[4U] << 8) + header[5U];
m_rfDataFrames = header[6U] & 0x7FU;

m_display->writeP25("DATA", false, llId, "R");
LogMessage("P25, received RF data transmission to %u, %u blocks", llId, m_rfDataFrames);
} else {
m_rfPDUCount = 0U;
m_rfPDUBits = 0U;
m_rfState = RS_RF_LISTENING;
m_rfDataFrames = 0U;
}
}

::memcpy(m_rfPDURaw + 2U + m_rfPDUCount * P25_LDU_FRAME_LENGTH_BYTES, data + 2U, P25_LDU_FRAME_LENGTH_BYTES);
m_rfPDUCount++;
if (m_rfState == RS_RF_DATA) {
m_rfPDUCount++;

if (m_rfPDUCount == 3U) {
// Regenerate Sync
CSync::addP25Sync(m_rfPDURaw + 2U);
unsigned int bitLength = ((m_rfDataFrames + 1U) * P25_PDU_FEC_LENGTH_BITS) + P25_SYNC_LENGTH_BITS + P25_NID_LENGTH_BITS;

// Regenerate NID
m_nid.encode(m_rfPDURaw + 2U, P25_DUID_PDU);
if (m_rfPDUBits >= bitLength) {
unsigned int offset = P25_SYNC_LENGTH_BYTES + P25_NID_LENGTH_BYTES;

// Add busy bits
addBusyBits(m_rfPDURaw + 2U, m_rfPDUCount * P25_LDU_FRAME_LENGTH_BITS, false, true);
// Regenerate the PDU header
CP25Trellis trellis;
unsigned char header[P25_PDU_HEADER_LENGTH_BYTES];
trellis.decode12(m_rfPDU + offset, header);
trellis.encode12(header, m_rfPDU + offset);
offset += P25_PDU_FEC_LENGTH_BITS;

if (m_duplex) {
m_rfPDURaw[0U] = TAG_DATA;
m_rfPDURaw[1U] = 0x00U;
writeQueueRF(m_rfPDURaw, m_rfPDUCount * P25_LDU_FRAME_LENGTH_BYTES + 2U);
// Regenerate the PDU data
for (unsigned int i = 0U; i < m_rfDataFrames; i++) {
unsigned char data[P25_PDU_CONFIRMED_LENGTH_BYTES];

bool valid = trellis.decode34(m_rfPDU + offset, data);
if (valid) {
trellis.encode34(data, m_rfPDU + offset);
} else {
valid = trellis.decode12(m_rfPDU + offset, data);
if (valid)
trellis.encode12(data, m_rfPDU + offset);
}

offset += P25_PDU_FEC_LENGTH_BITS;
}

unsigned char pdu[1024U];

// Add the data
CP25Utils::encode(m_rfPDU, pdu + 2U, 0U, bitLength);

// Regenerate Sync
CSync::addP25Sync(pdu + 2U);

// Regenerate NID
m_nid.encode(pdu + 2U, P25_DUID_PDU);

// Add busy bits
addBusyBits(pdu + 2U, bitLength, false, true);

if (m_duplex) {
unsigned int byteLength = bitLength / 8U;
if ((bitLength % 8U) > 0U)
byteLength++;

pdu[0U] = TAG_DATA;
pdu[1U] = 0x00U;
writeQueueRF(pdu, byteLength + 2U);
}

LogMessage("P25, ended RF data transmission");
m_display->clearP25();

m_rfPDUCount = 0U;
m_rfPDUBits = 0U;
m_rfState = RS_RF_LISTENING;
m_rfDataFrames = 0U;
}

m_rfPDUCount = 0U;
m_rfPDUBits = 0U;
m_rfState = RS_RF_LISTENING;
return true;
}
}

Expand Down
4 changes: 2 additions & 2 deletions P25Control.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class CP25Control {
unsigned int m_rfErrs;
unsigned int m_netFrames;
unsigned int m_netLost;
unsigned int m_rfDataFrames;
CP25NID m_nid;
unsigned char m_lastDUID;
CP25Audio m_audio;
Expand All @@ -77,8 +78,7 @@ class CP25Control {
unsigned char* m_netLDU2;
unsigned char* m_lastIMBE;
unsigned char* m_rfLDU;
unsigned char* m_rfPDURaw;
unsigned char* m_rfPDUCooked;
unsigned char* m_rfPDU;
unsigned int m_rfPDUCount;
unsigned int m_rfPDUBits;
CRSSIInterpolator* m_rssiMapper;
Expand Down
7 changes: 6 additions & 1 deletion P25Defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,12 @@ const unsigned char P25_SYNC_BYTES_LENGTH = 6U;

const unsigned int P25_MAX_PDU_COUNT = 10U;

const unsigned int P25_PDU_HEADER_LENGTH_BYTES = 12U;
const unsigned int P25_PDU_HEADER_LENGTH_BYTES = 12U;
const unsigned int P25_PDU_CONFIRMED_LENGTH_BYTES = 18U;
const unsigned int P25_PDU_UNCONFIRMED_LENGTH_BYTES = 12U;

const unsigned int P25_PDU_FEC_LENGTH_BYTES = 24U;
const unsigned int P25_PDU_FEC_LENGTH_BITS = P25_PDU_FEC_LENGTH_BYTES * 8U;

const unsigned int P25_MI_LENGTH_BYTES = 9U;

Expand Down
4 changes: 0 additions & 4 deletions P25Trellis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,11 +174,9 @@ void CP25Trellis::deinterleave(const unsigned char* data, signed char* dibits) c
{
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;
Expand Down Expand Up @@ -222,11 +220,9 @@ void CP25Trellis::interleave(const signed char* dibits, unsigned char* data) con
}

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);
}
}
Expand Down

0 comments on commit 082c2e1

Please sign in to comment.