Fix P25 data reception, regeneration, and transmission.

This commit is contained in:
Jonathan Naylor 2018-01-16 23:26:05 +00:00
parent 323179d525
commit 082c2e1b1f
4 changed files with 96 additions and 43 deletions

View File

@ -22,6 +22,7 @@
#include "P25Utils.h"
#include "Utils.h"
#include "Sync.h"
#include "CRC.h"
#include "Log.h"
#include <cassert>
@ -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(),
@ -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),
@ -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()
@ -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)
@ -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;
@ -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();
@ -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;
@ -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;
}
}

View File

@ -66,6 +66,7 @@ private:
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;
@ -77,8 +78,7 @@ private:
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;

View File

@ -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;

View File

@ -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;
@ -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);
}
}