remove standalone P25 DataRspHeader class and merge it into DataHeader; further enhance the P25 DataHeader to better match the TIA spec; clean up some code and variable references;

pull/12/head
Bryan Biedenkapp 4 years ago
parent 8207a35a84
commit e931d8d26e

@ -210,7 +210,6 @@
<ClInclude Include="p25\acl\AccessControl.h" />
<ClInclude Include="p25\data\DataBlock.h" />
<ClInclude Include="p25\data\DataHeader.h" />
<ClInclude Include="p25\data\DataRspHeader.h" />
<ClInclude Include="p25\data\LowSpeedData.h" />
<ClInclude Include="p25\dfsi\DFSIDefines.h" />
<ClInclude Include="p25\dfsi\LC.h" />
@ -290,7 +289,6 @@
<ClCompile Include="p25\acl\AccessControl.cpp" />
<ClCompile Include="p25\data\DataBlock.cpp" />
<ClCompile Include="p25\data\DataHeader.cpp" />
<ClCompile Include="p25\data\DataRspHeader.cpp" />
<ClCompile Include="p25\data\LowSpeedData.cpp" />
<ClCompile Include="p25\edac\Trellis.cpp" />
<ClCompile Include="p25\lc\LC.cpp" />

@ -338,9 +338,6 @@
<ClInclude Include="network\BaseNetwork.h">
<Filter>Header Files\network</Filter>
</ClInclude>
<ClInclude Include="p25\data\DataRspHeader.h">
<Filter>Header Files\p25\data</Filter>
</ClInclude>
<ClInclude Include="dmr\SiteData.h">
<Filter>Header Files\dmr</Filter>
</ClInclude>
@ -568,9 +565,6 @@
<ClCompile Include="network\BaseNetwork.cpp">
<Filter>Source Files\network</Filter>
</ClCompile>
<ClCompile Include="p25\data\DataRspHeader.cpp">
<Filter>Source Files\p25\data</Filter>
</ClCompile>
<ClCompile Include="dmr\ControlPacket.cpp">
<Filter>Source Files\dmr</Filter>
</ClCompile>

@ -42,7 +42,6 @@ OBJECTS = \
p25/acl/AccessControl.o \
p25/data/DataBlock.o \
p25/data/DataHeader.o \
p25/data/DataRspHeader.o \
p25/data/LowSpeedData.o \
p25/dfsi/LC.o \
p25/edac/Trellis.o \

@ -41,7 +41,6 @@ OBJECTS = \
p25/acl/AccessControl.o \
p25/data/DataBlock.o \
p25/data/DataHeader.o \
p25/data/DataRspHeader.o \
p25/data/LowSpeedData.o \
p25/dfsi/LC.o \
p25/edac/Trellis.o \

@ -42,7 +42,6 @@ OBJECTS = \
p25/acl/AccessControl.o \
p25/data/DataBlock.o \
p25/data/DataHeader.o \
p25/data/DataRspHeader.o \
p25/data/LowSpeedData.o \
p25/dfsi/LC.o \
p25/edac/Trellis.o \

@ -449,15 +449,15 @@ uint8_t CRC::crc8(const uint8_t *in, uint32_t length)
/// Generate 9-bit CRC.
/// </summary>
/// <param name="in">Input byte array.</param>
/// <param name="bitlen">Length of byte array in bits.</param>
/// <param name="bitLength">Length of byte array in bits.</param>
/// <returns>Calculated 9-bit CRC value.</returns>
uint16_t CRC::crc9(const uint8_t* in, uint32_t bitlen)
uint16_t CRC::crc9(const uint8_t* in, uint32_t bitLength)
{
assert(in != NULL);
uint16_t crc = 0x00U;
for (uint32_t i = 0; i < bitlen; i++) {
for (uint32_t i = 0; i < bitLength; i++) {
bool b = READ_BIT(in, i);
if (b) {
if (i < 7U) {
@ -473,7 +473,7 @@ uint16_t CRC::crc9(const uint8_t* in, uint32_t bitlen)
crc ^= 0x1FFU;
#if DEBUG_CRC
LogDebug(LOG_HOST, "CRC:crc9(), crc = $%03X, bitlen = %u", crc, bitlen);
LogDebug(LOG_HOST, "CRC:crc9(), crc = $%03X, bitlen = %u", crc, bitLength);
#endif
return crc;

@ -66,7 +66,7 @@ namespace edac
static uint8_t crc8(const uint8_t* in, uint32_t length);
/// <summary>Generate 9-bit CRC.</summary>
static uint16_t crc9(const uint8_t* in, uint32_t bitlen);
static uint16_t crc9(const uint8_t* in, uint32_t bitLength);
};
} // namespace edac

@ -13,7 +13,7 @@
/*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2017,2018 by Andy Uribe CA6JAU
* Copyright (C) 2017-2021 by Bryan Biedenkapp N2PLL
* Copyright (C) 2017-2022 by Bryan Biedenkapp N2PLL
*
* 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
@ -1741,9 +1741,10 @@ void HostCal::processP25BER(const uint8_t* buffer)
Utils::dump(1U, "Unfixable PDU Data", rfPDU + P25_SYNC_LENGTH_BYTES + P25_NID_LENGTH_BYTES, P25_PDU_HEADER_LENGTH_BYTES);
}
else {
LogMessage(LOG_CAL, P25_PDU_STR ", fmt = $%02X, sap = $%02X, fullMessage = %u, blocksToFollow = %u, padCount = %u, n = %u, seqNo = %u",
dataHeader.getFormat(), dataHeader.getSAP(), dataHeader.getFullMessage(), dataHeader.getBlocksToFollow(), dataHeader.getPadCount(),
dataHeader.getN(), dataHeader.getSeqNo());
LogMessage(LOG_CAL, P25_PDU_STR ", ack = %u, outbound = %u, fmt = $%02X, mfId = $%02X, sap = $%02X, fullMessage = %u, blocksToFollow = %u, padCount = %u, n = %u, seqNo = %u, lastFragment = %u, hdrOffset = %u",
dataHeader.getAckNeeded(), dataHeader.getOutbound(), dataHeader.getFormat(), dataHeader.getMFId(), dataHeader.getSAP(), dataHeader.getFullMessage(),
dataHeader.getBlocksToFollow(), dataHeader.getPadCount(), dataHeader.getNs(), dataHeader.getFSN(), dataHeader.getLastFragment(),
dataHeader.getHeaderOffset());
}
delete[] rfPDU;

@ -96,7 +96,9 @@ bool DataPacket::process(uint8_t* data, uint32_t len)
m_rfDataBlockCnt = 0U;
m_rfPDUCount = 0U;
m_rfPDUBits = 0U;
::memset(m_rfPDU, 0x00U, P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES + 2U);
m_p25->m_rfState = RS_RF_DATA;
::memset(m_pduUserData, 0x00U, P25_MAX_PDU_COUNT * P25_PDU_CONFIRMED_LENGTH_BYTES + 2U);
@ -131,9 +133,9 @@ bool DataPacket::process(uint8_t* data, uint32_t len)
}
if (m_verbose) {
LogMessage(LOG_RF, P25_PDU_STR ", ack = %u, outbound = %u, fmt = $%02X, sap = $%02X, fullMessage = %u, blocksToFollow = %u, padCount = %u, n = %u, seqNo = %u, hdrOffset = %u",
m_rfDataHeader.getAckNeeded(), m_rfDataHeader.getOutbound(), m_rfDataHeader.getFormat(), m_rfDataHeader.getSAP(), m_rfDataHeader.getFullMessage(),
m_rfDataHeader.getBlocksToFollow(), m_rfDataHeader.getPadCount(), m_rfDataHeader.getN(), m_rfDataHeader.getSeqNo(),
LogMessage(LOG_RF, P25_PDU_STR ", ack = %u, outbound = %u, fmt = $%02X, mfId = $%02X, sap = $%02X, fullMessage = %u, blocksToFollow = %u, padCount = %u, n = %u, seqNo = %u, lastFragment = %u, hdrOffset = %u",
m_rfDataHeader.getAckNeeded(), m_rfDataHeader.getOutbound(), m_rfDataHeader.getFormat(), m_rfDataHeader.getMFId(), m_rfDataHeader.getSAP(), m_rfDataHeader.getFullMessage(),
m_rfDataHeader.getBlocksToFollow(), m_rfDataHeader.getPadCount(), m_rfDataHeader.getNs(), m_rfDataHeader.getFSN(), m_rfDataHeader.getLastFragment(),
m_rfDataHeader.getHeaderOffset());
}
@ -175,9 +177,9 @@ bool DataPacket::process(uint8_t* data, uint32_t len)
}
if (m_verbose) {
LogMessage(LOG_RF, P25_PDU_STR ", fmt = $%02X, sap = $%02X, fullMessage = %u, blocksToFollow = %u, padCount = %u, n = %u, seqNo = %u, hdrOffset = %u, llId = %u",
m_rfSecondHeader.getFormat(), m_rfSecondHeader.getSAP(), m_rfSecondHeader.getFullMessage(),
m_rfSecondHeader.getBlocksToFollow(), m_rfSecondHeader.getPadCount(), m_rfSecondHeader.getN(), m_rfSecondHeader.getSeqNo(),
LogMessage(LOG_RF, P25_PDU_STR ", fmt = $%02X, mfId = $%02X, sap = $%02X, fullMessage = %u, blocksToFollow = %u, padCount = %u, n = %u, seqNo = %u, lastFragment = %u, hdrOffset = %u, llId = %u",
m_rfSecondHeader.getFormat(), m_rfSecondHeader.getMFId(), m_rfSecondHeader.getSAP(), m_rfSecondHeader.getFullMessage(),
m_rfSecondHeader.getBlocksToFollow(), m_rfSecondHeader.getPadCount(), m_rfSecondHeader.getNs(), m_rfSecondHeader.getFSN(), m_rfSecondHeader.getLastFragment(),
m_rfSecondHeader.getHeaderOffset(), m_rfSecondHeader.getLLId());
}
@ -334,7 +336,7 @@ bool DataPacket::process(uint8_t* data, uint32_t len)
LogMessage(LOG_RF, P25_PDU_STR ", repeating PDU, llId = %u", (m_rfUseSecondHeader) ? m_rfSecondHeader.getLLId() : m_rfDataHeader.getLLId());
}
writeRF_PDU(); // re-generate PDU and send it on
writeRF_PDU_Buffered(); // re-generate buffered PDU and send it on
}
::ActivityLog("P25", true, "end of RF data transmission");
@ -607,29 +609,76 @@ void DataPacket::writeNetworkRF(const uint8_t dataType, const uint8_t *data, uin
/// <summary>
/// Helper to write a P25 PDU packet.
/// </summary>
void DataPacket::writeRF_PDU()
/// <param name="pdu"></param>
/// <param name="bitlength"></param>
/// <param name="noNulls"></param>
/// <remarks>This simply takes data packed into m_rfPDU and transmits it.</remarks>
void DataPacket::writeRF_PDU(const uint8_t* pdu, uint32_t bitLength, bool noNulls)
{
assert(pdu != NULL);
assert(bitLength > 0U);
uint8_t data[P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES + 2U];
::memset(data, 0x00U, P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES + 2U);
if (m_debug) {
Utils::dump(2U, "!!! *Raw PDU Frame Data - P25_DUID_PDU", pdu, bitLength / 8U);
}
// Add the data
uint32_t newBitLength = P25Utils::encode(pdu, data + 2U, bitLength);
uint32_t newByteLength = newBitLength / 8U;
if ((newBitLength % 8U) > 0U)
newByteLength++;
// Regenerate Sync
Sync::addP25Sync(data + 2U);
// Regenerate NID
m_p25->m_nid.encode(data + 2U, P25_DUID_PDU);
// Add busy bits
m_p25->addBusyBits(data + 2U, newBitLength, false, true);
if (m_p25->m_duplex) {
data[0U] = TAG_DATA;
data[1U] = 0x00U;
m_p25->writeQueueRF(data, newByteLength + 2U);
}
// add trailing null pad; only if control data isn't being transmitted
if (!m_p25->m_ccRunning && !noNulls) {
m_p25->writeRF_Nulls();
}
}
/// <summary>
/// Helper to re-write a received P25 PDU packet.
/// </summary>
/// <remarks>This will take buffered received PDU data and repeat it over the air.</remarks>
void DataPacket::writeRF_PDU_Buffered()
{
uint32_t bitLength = ((m_rfDataHeader.getBlocksToFollow() + 1U) * P25_PDU_FEC_LENGTH_BITS) + P25_PREAMBLE_LENGTH_BITS;
uint32_t offset = P25_PREAMBLE_LENGTH_BITS;
::memset(m_rfPDU, 0x00U, P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES + 2U);
uint8_t buffer[P25_PDU_FEC_LENGTH_BYTES];
::memset(buffer, 0x00U, P25_PDU_FEC_LENGTH_BYTES);
uint8_t data[bitLength / 8U];
::memset(data, 0x00U, bitLength / 8U);
uint8_t block[P25_PDU_FEC_LENGTH_BYTES];
::memset(block, 0x00U, P25_PDU_FEC_LENGTH_BYTES);
uint32_t blocksToFollow = m_rfDataHeader.getBlocksToFollow();
// Generate the PDU header and 1/2 rate Trellis
m_rfDataHeader.encode(buffer);
Utils::setBitRange(buffer, m_rfPDU, offset, P25_PDU_FEC_LENGTH_BITS);
m_rfDataHeader.encode(block);
Utils::setBitRange(block, data, offset, P25_PDU_FEC_LENGTH_BITS);
offset += P25_PDU_FEC_LENGTH_BITS;
// Generate the second PDU header
if (m_rfUseSecondHeader) {
::memset(buffer, 0x00U, P25_PDU_FEC_LENGTH_BYTES);
::memset(block, 0x00U, P25_PDU_FEC_LENGTH_BYTES);
m_rfSecondHeader.encode(buffer);
Utils::setBitRange(buffer, m_rfPDU, offset, P25_PDU_FEC_LENGTH_BITS);
m_rfSecondHeader.encode(block);
Utils::setBitRange(block, data, offset, P25_PDU_FEC_LENGTH_BITS);
offset += P25_PDU_FEC_LENGTH_BITS;
blocksToFollow--;
@ -642,47 +691,15 @@ void DataPacket::writeRF_PDU()
m_rfData[i].setSerialNo(i);
m_rfData[i].setData(m_pduUserData + dataOffset);
::memset(buffer, 0x00U, P25_PDU_FEC_LENGTH_BYTES);
m_rfData[i].encode(buffer);
Utils::setBitRange(buffer, m_rfPDU, offset, P25_PDU_FEC_LENGTH_BITS);
::memset(block, 0x00U, P25_PDU_FEC_LENGTH_BYTES);
m_rfData[i].encode(block);
Utils::setBitRange(block, data, offset, P25_PDU_FEC_LENGTH_BITS);
offset += P25_PDU_FEC_LENGTH_BITS;
dataOffset += (m_rfDataHeader.getFormat() == PDU_FMT_CONFIRMED) ? P25_PDU_CONFIRMED_DATA_LENGTH_BYTES : P25_PDU_UNCONFIRMED_LENGTH_BYTES;
}
if (m_debug) {
Utils::dump(2U, "!!! *Raw PDU Frame Data - P25_DUID_PDU", m_rfPDU, bitLength / 8U);
}
uint8_t pdu[P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES + 2U];
// Add the data
uint32_t newBitLength = P25Utils::encode(m_rfPDU, pdu + 2U, bitLength);
uint32_t newByteLength = newBitLength / 8U;
if ((newBitLength % 8U) > 0U)
newByteLength++;
// Regenerate Sync
Sync::addP25Sync(pdu + 2U);
// Regenerate NID
m_p25->m_nid.encode(pdu + 2U, P25_DUID_PDU);
// Add busy bits
m_p25->addBusyBits(pdu + 2U, newBitLength, false, true);
::memset(m_rfPDU, 0x00U, P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES + 2U);
if (m_p25->m_duplex) {
pdu[0U] = TAG_DATA;
pdu[1U] = 0x00U;
m_p25->writeQueueRF(pdu, newByteLength + 2U);
}
// add trailing null pad; only if control data isn't being transmitted
if (!m_p25->m_ccRunning) {
m_p25->writeRF_Nulls();
}
writeRF_PDU(data, bitLength);
}
/// <summary>
@ -696,85 +713,62 @@ void DataPacket::writeRF_PDU_Reg_Response(uint8_t regType, uint32_t llId, ulong6
if ((regType != PDU_REG_TYPE_RSP_ACCPT) && (regType != PDU_REG_TYPE_RSP_DENY))
return;
uint32_t bitLength = (2U * P25_PDU_FEC_LENGTH_BITS); // + P25_PREAMBLE_LENGTH_BITS;
uint32_t bitLength = (2U * P25_PDU_FEC_LENGTH_BITS) + P25_PREAMBLE_LENGTH_BITS;
uint32_t offset = P25_PREAMBLE_LENGTH_BITS;
uint8_t buffer[P25_PDU_FEC_LENGTH_BYTES];
::memset(buffer, 0x00U, P25_PDU_FEC_LENGTH_BYTES);
uint8_t data[bitLength / 8U];
::memset(data, 0x00U, bitLength / 8U);
uint8_t block[P25_PDU_FEC_LENGTH_BYTES];
::memset(block, 0x00U, P25_PDU_FEC_LENGTH_BYTES);
DataRspHeader rspHeader = DataRspHeader();
DataHeader rspHeader = DataHeader();
rspHeader.setFormat(PDU_FMT_RSP);
rspHeader.setOutbound(true);
rspHeader.setClass(PDU_ACK_CLASS_ACK);
rspHeader.setType(PDU_ACK_TYPE_ACK);
rspHeader.setStatus(m_rfDataHeader.getNs());
rspHeader.setLLId(llId);
if (m_rfDataHeader.getSAP() == PDU_SAP_EXT_ADDR) {
rspHeader.setSrcLLId(P25_WUID_FNE);
rspHeader.setExtended(true);
rspHeader.setFullMessage(true);
}
else {
rspHeader.setExtended(false);
rspHeader.setFullMessage(false);
}
rspHeader.setBlocksToFollow(1U);
// Generate the PDU header and 1/2 rate Trellis
rspHeader.encode(buffer);
Utils::setBitRange(buffer, m_rfPDU, offset, P25_PDU_FEC_LENGTH_BITS);
rspHeader.encode(block);
Utils::setBitRange(block, data, offset, P25_PDU_FEC_LENGTH_BITS);
offset += P25_PDU_FEC_LENGTH_BITS;
// build registration response data
::memset(buffer, 0x00U, P25_PDU_CONFIRMED_DATA_LENGTH_BYTES);
::memset(block, 0x00U, P25_PDU_CONFIRMED_DATA_LENGTH_BYTES);
buffer[0U] = (regType << 4); // Registration Type & Options
buffer[1U] = (llId >> 16) & 0xFFU; // Logical Link ID
buffer[2U] = (llId >> 8) & 0xFFU;
buffer[3U] = (llId >> 0) & 0xFFU;
block[0U] = (regType << 4); // Registration Type & Options
block[1U] = (llId >> 16) & 0xFFU; // Logical Link ID
block[2U] = (llId >> 8) & 0xFFU;
block[3U] = (llId >> 0) & 0xFFU;
if (regType == PDU_REG_TYPE_RSP_ACCPT) {
buffer[8U] = (ipAddr >> 24) & 0xFFU; // IP Address
buffer[9U] = (ipAddr >> 16) & 0xFFU;
buffer[10U] = (ipAddr >> 8) & 0xFFU;
buffer[11U] = (ipAddr >> 0) & 0xFFU;
block[8U] = (ipAddr >> 24) & 0xFFU; // IP Address
block[9U] = (ipAddr >> 16) & 0xFFU;
block[10U] = (ipAddr >> 8) & 0xFFU;
block[11U] = (ipAddr >> 0) & 0xFFU;
}
edac::CRC::addCRC32(buffer, P25_PDU_CONFIRMED_DATA_LENGTH_BYTES);
edac::CRC::addCRC32(block, P25_PDU_CONFIRMED_DATA_LENGTH_BYTES);
// Generate the PDU data
m_rfData[0].setFormat(PDU_FMT_RSP);
m_rfData[0].setConfirmed(true);
m_rfData[0].setSerialNo(0U);
m_rfData[0].setData(buffer);
m_rfData[0].setData(block);
::memset(buffer, 0x00U, P25_PDU_FEC_LENGTH_BYTES);
m_rfData[0].encode(buffer);
Utils::setBitRange(buffer, m_rfPDU, offset, P25_PDU_FEC_LENGTH_BITS);
::memset(block, 0x00U, P25_PDU_FEC_LENGTH_BYTES);
m_rfData[0].encode(block);
Utils::setBitRange(block, data, offset, P25_PDU_FEC_LENGTH_BITS);
if (m_debug) {
Utils::dump(2U, "!!! *Raw PDU Frame Data - P25_DUID_PDU", m_rfPDU, bitLength / 8U);
}
uint8_t pdu[P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES + 2U];
// Regenerate Sync
Sync::addP25Sync(pdu + 2U);
// Regenerate NID
m_p25->m_nid.encode(pdu + 2U, P25_DUID_PDU);
// Add the data
uint32_t newBitLength = P25Utils::encode(m_rfPDU, pdu + 2U, 114U, bitLength);
uint32_t newByteLength = newBitLength / 8U;
if ((newBitLength % 8U) > 0U)
newByteLength++;
// Add busy bits
m_p25->addBusyBits(pdu + 2U, newBitLength, false, true);
::memset(m_rfPDU, 0x00U, P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES + 2U);
if (m_p25->m_duplex) {
pdu[0U] = TAG_DATA;
pdu[1U] = 0x00U;
m_p25->writeQueueRF(pdu, newByteLength + 2U);
}
writeRF_PDU(data, bitLength);
}
/// <summary>
@ -788,52 +782,35 @@ void DataPacket::writeRF_PDU_Ack_Response(uint8_t ackClass, uint8_t ackType, uin
if (ackClass == PDU_ACK_CLASS_ACK && ackType != PDU_ACK_TYPE_ACK)
return;
uint32_t bitLength = (2U * P25_PDU_FEC_LENGTH_BITS); // + P25_PREAMBLE_LENGTH_BITS;
uint32_t bitLength = (2U * P25_PDU_FEC_LENGTH_BITS) + P25_PREAMBLE_LENGTH_BITS;
uint32_t offset = P25_PREAMBLE_LENGTH_BITS;
uint8_t buffer[P25_PDU_FEC_LENGTH_BYTES];
::memset(buffer, 0x00U, P25_PDU_FEC_LENGTH_BYTES);
uint8_t data[bitLength / 8U];
::memset(data, 0x00U, bitLength / 8U);
uint8_t block[P25_PDU_FEC_LENGTH_BYTES];
::memset(block, 0x00U, P25_PDU_FEC_LENGTH_BYTES);
DataRspHeader rspHeader = DataRspHeader();
DataHeader rspHeader = DataHeader();
rspHeader.setFormat(PDU_FMT_RSP);
rspHeader.setOutbound(true);
rspHeader.setClass(ackClass);
rspHeader.setType(ackType);
rspHeader.setStatus(m_rfDataHeader.getNs());
rspHeader.setLLId(llId);
rspHeader.setSrcLLId(P25_WUID_FNE);
if (m_rfDataHeader.getSAP() == PDU_SAP_EXT_ADDR) {
rspHeader.setSrcLLId(P25_WUID_FNE);
rspHeader.setFullMessage(true);
}
else {
rspHeader.setFullMessage(false);
}
rspHeader.setBlocksToFollow(0U);
// Generate the PDU header and 1/2 rate Trellis
rspHeader.encode(buffer);
Utils::setBitRange(buffer, m_rfPDU, offset, P25_PDU_FEC_LENGTH_BITS);
if (m_debug) {
Utils::dump(2U, "!!! *Raw PDU Frame Data - P25_DUID_PDU", m_rfPDU, bitLength / 8U);
}
uint8_t pdu[P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES + 2U];
// Regenerate Sync
Sync::addP25Sync(pdu + 2U);
// Regenerate NID
m_p25->m_nid.encode(pdu + 2U, P25_DUID_PDU);
// Add the data
uint32_t newBitLength = P25Utils::encode(m_rfPDU, pdu + 2U, 114U, bitLength);
uint32_t newByteLength = newBitLength / 8U;
if ((newBitLength % 8U) > 0U)
newByteLength++;
rspHeader.encode(block);
Utils::setBitRange(block, data, offset, P25_PDU_FEC_LENGTH_BITS);
// Add busy bits
m_p25->addBusyBits(pdu + 2U, newBitLength, false, true);
::memset(m_rfPDU, 0x00U, P25_MAX_PDU_COUNT * P25_LDU_FRAME_LENGTH_BYTES + 2U);
if (m_p25->m_duplex) {
pdu[0U] = TAG_DATA;
pdu[1U] = 0x00U;
m_p25->writeQueueRF(pdu, newByteLength + 2U);
}
writeRF_PDU(data, bitLength);
}
/// <summary>
@ -875,7 +852,7 @@ void DataPacket::writeNet_PDU_Header()
if (m_verbose) {
LogMessage(LOG_NET, P25_PDU_STR ", ack = %u, outbound = %u, fmt = $%02X, sap = $%02X, fullMessage = %u, blocksToFollow = %u, padCount = %u, n = %u, seqNo = %u, hdrOffset = %u",
m_netDataHeader.getAckNeeded(), m_netDataHeader.getOutbound(), m_netDataHeader.getFormat(), m_netDataHeader.getSAP(), m_netDataHeader.getFullMessage(),
m_netDataHeader.getBlocksToFollow(), m_netDataHeader.getPadCount(), m_netDataHeader.getN(), m_netDataHeader.getSeqNo(),
m_netDataHeader.getBlocksToFollow(), m_netDataHeader.getPadCount(), m_netDataHeader.getNs(), m_netDataHeader.getFSN(),
m_netDataHeader.getHeaderOffset());
}

@ -34,7 +34,6 @@
#include "Defines.h"
#include "p25/data/DataBlock.h"
#include "p25/data/DataHeader.h"
#include "p25/data/DataRspHeader.h"
#include "p25/data/LowSpeedData.h"
#include "p25/lc/LC.h"
#include "p25/Control.h"
@ -115,7 +114,9 @@ namespace p25
void writeNetworkRF(const uint8_t dataType, const uint8_t* data, uint32_t len);
/// <summary>Helper to write a P25 PDU packet.</summary>
void writeRF_PDU();
void writeRF_PDU(const uint8_t* pdu, uint32_t bitLength, bool noNulls = false);
/// <summary>Helper to re-write a received P25 PDU packet.</summary>
void writeRF_PDU_Buffered();
/// <summary>Helper to write a PDU registration response.</summary>
void writeRF_PDU_Reg_Response(uint8_t regType, uint32_t llId, ulong64_t ipAddr);
/// <summary>Helper to write a PDU acknowledge response.</summary>

@ -74,6 +74,7 @@ namespace p25
/// <summary>Flag indicating this is the last block in a sequence of block.</summary>
__PROPERTY(bool, lastBlock, LastBlock);
/// <summary>Logical link ID.</summary>
__PROPERTY(uint32_t, llId, LLId);
/// <summary>Service access point.</summary>

@ -49,12 +49,19 @@ DataHeader::DataHeader() :
m_sap(0U),
m_mfId(P25_MFG_STANDARD),
m_llId(0U),
m_fullMessage(false),
m_sync(false),
m_n(0U),
m_seqNo(0U),
m_F(true),
m_S(false),
m_fsn(0U),
m_Ns(0U),
m_lastFragment(true),
m_headerOffset(0U),
m_srcLlId(0U),
m_rspClass(PDU_ACK_CLASS_NACK),
m_rspType(PDU_ACK_TYPE_NACK_ILLEGAL),
m_rspStatus(0U),
m_ambtOpcode(0U),
m_ambtField8(0U),
m_ambtField9(0U),
m_trellis(),
m_blocksToFollow(0U),
m_padCount(0U),
@ -97,23 +104,20 @@ bool DataHeader::decode(const uint8_t* data)
m_ackNeeded = (header[0U] & 0x40U) == 0x40U; // Acknowledge Needed
m_outbound = (header[0U] & 0x20U) == 0x20U; // Inbound/Outbound
m_fmt = header[0U] & 0x1F; // Packet Format
m_sap = header[1U] & 0x3FU; // Service Access Point
m_mfId = header[2U]; // Mfg Id.
m_llId = (header[3U] << 16) + (header[4U] << 8) + header[5U]; // Logical Link ID
m_fullMessage = (header[6U] & 0x80U) == 0x80U; // Full Message Flag
m_F = (header[6U] & 0x80U) == 0x80U; // Full Message Flag
m_blocksToFollow = header[6U] & 0x7FU; // Block Frames to Follow
if (m_fmt == PDU_FMT_AMBT) {
m_padCount = header[7U] & 0x1FU; // Pad Count
if (m_fmt == PDU_FMT_RSP || m_fmt == PDU_FMT_AMBT) {
m_padCount = 0;
m_ambtOpcode = header[7U] & 0x3FU; // AMBT Opcode
}
else {
m_padCount = header[7U] & 0x1FU; // Pad Count
}
if (m_fmt == PDU_FMT_CONFIRMED) {
@ -123,23 +127,40 @@ bool DataHeader::decode(const uint8_t* data)
m_dataOctets = 12 * m_blocksToFollow - 4 - m_padCount;
}
if (m_fmt == PDU_FMT_AMBT) {
m_sync = false;
switch (m_fmt) {
case PDU_FMT_CONFIRMED:
m_S = (header[8U] & 0x80U) == 0x80U; // Re-synchronize Flag
m_n = 0U;
m_seqNo = 0U;
m_headerOffset = 0U;
m_Ns = (header[8U] >> 4) & 0x07U; // Packet Sequence No.
m_fsn = header[8U] & 0x07U; // Fragment Sequence No.
m_lastFragment = (header[8U] & 0x08U) == 0x08U; // Last Fragment Flag
m_headerOffset = header[9U] & 0x3FU; // Data Header Offset
break;
case PDU_FMT_RSP:
m_ackNeeded = false;
m_sap = PDU_SAP_USER_DATA;
m_rspClass = (header[1U] >> 6) & 0x03U; // Response Class
m_rspType = (header[1U] >> 3) & 0x07U; // Response Type
m_rspStatus = header[1U] & 0x07U; // Response Status
if (!m_F) {
m_srcLlId = (header[7U] << 16) + (header[8U] << 8) + header[9U]; // Source Logical Link ID
}
break;
case PDU_FMT_AMBT:
m_ambtOpcode = header[7U] & 0x3FU; // AMBT Opcode
m_ambtField8 = header[8U]; // AMBT Field 8
m_ambtField9 = header[9U]; // AMBT Field 9
}
else {
m_sync = (header[8U] & 0x80U) == 0x80U; // Re-synchronize Flag
m_n = (header[8U] >> 4) & 0x07U; // Packet Sequence No.
m_seqNo = header[8U] & 0x0FU; // Fragment Sequence No.
m_headerOffset = header[9U] & 0x3FU; // Data Header Offset
// fall-thru
case PDU_FMT_UNCONFIRMED:
default:
m_ackNeeded = false;
m_S = false;
m_Ns = 0U;
m_fsn = 0U;
m_headerOffset = 0U;
break;
}
return true;
@ -156,6 +177,10 @@ void DataHeader::encode(uint8_t* data)
uint8_t header[P25_PDU_HEADER_LENGTH_BYTES];
::memset(header, 0x00U, P25_PDU_HEADER_LENGTH_BYTES);
if (m_fmt == PDU_FMT_UNCONFIRMED || m_fmt == PDU_FMT_RSP) {
m_ackNeeded = false;
}
header[0U] = (m_ackNeeded ? 0x40U : 0x00U) + // Acknowledge Needed
(m_outbound ? 0x20U : 0x00U) + // Inbound/Outbound
(m_fmt & 0x1FU); // Packet Format
@ -169,29 +194,47 @@ void DataHeader::encode(uint8_t* data)
header[4U] = (m_llId >> 8) & 0xFFU;
header[5U] = (m_llId >> 0) & 0xFFU;
header[6U] = (m_fullMessage ? 0x80U : 0x00U) + // Full Message Flag
header[6U] = (m_F ? 0x80U : 0x00U) + // Full Message Flag
(m_blocksToFollow & 0x7FU); // Blocks Frames to Follow
if (m_fmt == PDU_FMT_AMBT) {
header[7U] = (m_ambtOpcode & 0x3FU); // AMBT Opcode
header[8U] = m_ambtField8; // AMBT Field 8
header[9U] = m_ambtField9; // AMBT Field 9
}
else {
switch (m_fmt) {
case PDU_FMT_CONFIRMED:
header[7U] = (m_padCount & 0x1FU); // Pad Count
header[8U] = (m_sync ? 0x80U : 0x00U) + // Re-synchronize Flag
((m_n << 4) & 0x07U) + // Packet Sequence No.
(m_seqNo & 0x0F); // Fragment Sequence No.
header[8U] = (m_S ? 0x80U : 0x00U) + // Re-synchronize Flag
((m_Ns << 4) & 0x07U) + // Packet Sequence No.
(m_lastFragment ? 0x08U : 0x00U) + // Last Fragment Flag
(m_fsn & 0x07); // Fragment Sequence No.
header[9U] = m_headerOffset & 0x3FU; // Data Header Offset
break;
case PDU_FMT_RSP:
header[1U] = ((m_rspClass & 0x03U) << 6) + // Response Class
((m_rspType & 0x07U) << 3) + // Response Type
((m_rspStatus & 0x07U)); // Response Status
if (!m_F) {
header[7U] = (m_srcLlId >> 16) & 0xFFU; // Source Logical Link ID
header[8U] = (m_srcLlId >> 8) & 0xFFU;
header[9U] = (m_srcLlId >> 0) & 0xFFU;
}
break;
case PDU_FMT_AMBT:
header[7U] = (m_ambtOpcode & 0x3FU); // AMBT Opcode
header[8U] = m_ambtField8; // AMBT Field 8
header[9U] = m_ambtField9; // AMBT Field 9
break;
case PDU_FMT_UNCONFIRMED:
default:
header[8U] = 0x00U;
header[9U] = m_headerOffset & 0x3FU; // Data Header Offset
break;
}
// compute CRC-CCITT 16
edac::CRC::addCCITT162(header, P25_PDU_HEADER_LENGTH_BYTES);
#if DEBUG_P25_PDU_DATA
Utils::dump(1U, "P25, DataHeader::encode(), PDU Header Data", data, P25_PDU_HEADER_LENGTH_BYTES);
Utils::dump(1U, "P25, DataHeader::encode(), PDU Header Data", header, P25_PDU_HEADER_LENGTH_BYTES);
#endif
// encode 1/2 rate Trellis
@ -212,19 +255,28 @@ void DataHeader::reset()
m_mfId = P25_MFG_STANDARD;
m_llId = 0U;
m_fullMessage = false;
m_F = true;
m_blocksToFollow = 0U;
m_padCount = 0U;
m_dataOctets = 0U;
m_sync = false;
m_S = false;
m_n = 0U;
m_seqNo = 0U;
m_Ns = 0U;
m_fsn = 0U;
m_lastFragment = true;
m_headerOffset = 0U;
m_srcLlId = 0U;
m_rspClass = PDU_ACK_CLASS_NACK;
m_rspType = PDU_ACK_TYPE_NACK_ILLEGAL;
m_rspStatus = 0U;
m_ambtOpcode = 0U;
m_ambtField8 = 0U;
m_ambtField9 = 0U;
}
/// <summary>Gets the total number of data octets.</summary>

@ -82,16 +82,30 @@ namespace p25
/// <summary>Logical link ID.</summary>
__PROPERTY(uint32_t, llId, LLId);
/// <summary>Flag indicating whether or not this data packet is a full message.</summary>
__PROPERTY(bool, fullMessage, FullMessage);
/// <summary></summary>
__PROPERTY(bool, sync, Sync);
/// <summary></summary>
__PROPERTY(uint8_t, n, N);
/// <summary>Data packet sequence number.</summary>
__PROPERTY(uint8_t, seqNo, SeqNo);
/// <remarks>When a response header, this represents the extended flag.</summary>
__PROPERTY(bool, F, FullMessage);
/// <summary>Synchronize Flag.</summary>
__PROPERTY(bool, S, Synchronize);
/// <summary>Fragment Sequence Number.</summary>
__PROPERTY(uint8_t, fsn, FSN);
/// <summary>Send Sequence Number.</summary>
__PROPERTY(uint8_t, Ns, Ns);
/// <summary>Flag indicating whether or not this is the last fragment in a message.</summary>
__PROPERTY(bool, lastFragment, LastFragment);
/// <summary>Offset of the header.</summary>
__PROPERTY(uint8_t, headerOffset, HeaderOffset);
/** Response Data */
/// <summary>Source Logical link ID.</summary>
__PROPERTY(uint32_t, srcLlId, SrcLLId);
/// <summary>Response class.</summary>
__PROPERTY(uint8_t, rspClass, Class);
/// <summary>Response type.</summary>
__PROPERTY(uint8_t, rspType, Type);
/// <summary>Response status.</summary>
__PROPERTY(uint8_t, rspStatus, Status);
/** AMBT Data */
/// <summary>Alternate Trunking Block Opcode</summary>
__PROPERTY(uint8_t, ambtOpcode, AMBTOpcode);
/// <summary>Alternate Trunking Block Field 8</summary>

@ -1,198 +0,0 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
/*
* Copyright (C) 2020,2022 by Bryan Biedenkapp N2PLL
*
* 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 "Defines.h"
#include "p25/P25Defines.h"
#include "p25/data/DataRspHeader.h"
#include "edac/CRC.h"
#include "Utils.h"
using namespace p25::data;
using namespace p25;
#include <cstdio>
#include <cassert>
#include <cstring>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the DataRspHeader class.
/// </summary>
DataRspHeader::DataRspHeader() :
m_outbound(true),
m_rspClass(PDU_ACK_CLASS_NACK),
m_rspType(PDU_ACK_TYPE_NACK_ILLEGAL),
m_rspStatus(0U),
m_mfId(P25_MFG_STANDARD),
m_llId(0U),
m_srcLlId(0U),
m_extended(true),
m_trellis(),
m_blocksToFollow(0U),
m_dataOctets(0U)
{
/* stub */
}
/// <summary>
/// Finalizes a instance of the DataRspHeader class.
/// </summary>
DataRspHeader::~DataRspHeader()
{
/* stub */
}
/// <summary>
/// Decodes P25 PDU data response header.
/// </summary>
/// <param name="data"></param>
/// <returns>True, if PDU data response header was decoded, otherwise false.</returns>
bool DataRspHeader::decode(const uint8_t* data)
{
assert(data != NULL);
uint8_t header[P25_PDU_HEADER_LENGTH_BYTES];
::memset(header, 0x00U, P25_PDU_HEADER_LENGTH_BYTES);
// decode 1/2 rate Trellis & check CRC-CCITT 16
bool valid = m_trellis.decode12(data, header);
if (valid)
valid = edac::CRC::checkCCITT162(header, P25_PDU_HEADER_LENGTH_BYTES);
if (!valid) {
return false;
}
#if DEBUG_P25_PDU_DATA
Utils::dump(1U, "P25, DataRspHeader::decode(), PDU Response Header Data", data, P25_PDU_HEADER_LENGTH_BYTES);
#endif
m_outbound = (header[0U] & 0x20U) == 0x20U; // Inbound/Outbound
m_rspClass = (header[1U] >> 6) & 0x03U; // Response Class
m_rspType = (header[1U] >> 3) & 0x07U; // Response Type
m_rspStatus = header[1U] & 0x07U; // Response Status
m_mfId = header[2U]; // Mfg Id.
m_llId = (header[3U] << 16) + (header[4U] << 8) + header[5U]; // Logical Link ID
m_extended = (header[6U] & 0x80U) == 0x80U; // Extended Addressing
m_blocksToFollow = header[6U] & 0x7FU; // Block Frames to Follow
m_srcLlId = (header[7U] << 16) + (header[8U] << 8) + header[9U]; // Source Logical Link ID
return true;
}
/// <summary>
/// Encodes P25 PDU data response header.
/// </summary>
/// <param name="data"></param>
void DataRspHeader::encode(uint8_t* data)
{
assert(data != NULL);
uint8_t header[P25_PDU_HEADER_LENGTH_BYTES];
::memset(header, 0x00U, P25_PDU_HEADER_LENGTH_BYTES);
header[0U] = PDU_FMT_RSP;
header[0U] = (m_outbound ? 0x20U : 0x00U) + // Inbound/Outbound
(PDU_FMT_RSP & 0x1FU); // Packet Format
header[1U] = ((m_rspClass & 0x03U) << 6) + // Response Class
((m_rspType & 0x07U) << 3) + // Response Type
((m_rspStatus & 0x07U)); // Response Status
header[2U] = m_mfId; // Mfg Id.
header[3U] = (m_llId >> 16) & 0xFFU; // Logical Link ID
header[4U] = (m_llId >> 8) & 0xFFU;
header[5U] = (m_llId >> 0) & 0xFFU;
header[6U] = (m_extended ? 0x80U : 0x00U) + // Extended Addressing
(m_blocksToFollow & 0x7FU); // Blocks Frames to Follow
header[7U] = (m_srcLlId >> 16) & 0xFFU; // Source Logical Link ID
header[8U] = (m_srcLlId >> 8) & 0xFFU;
header[9U] = (m_srcLlId >> 0) & 0xFFU;
// compute CRC-CCITT 16
edac::CRC::addCCITT162(header, P25_PDU_HEADER_LENGTH_BYTES);
#if DEBUG_P25_PDU_DATA
Utils::dump(1U, "P25, DataRspHeader::encode(), PDU Response Header Data", header, P25_PDU_HEADER_LENGTH_BYTES);
#endif
// encode 1/2 rate Trellis
m_trellis.encode12(header, data);
}
/// <summary>
/// Helper to reset data values to defaults.
/// </summary>
void DataRspHeader::reset()
{
m_outbound = false;
m_rspClass = PDU_ACK_CLASS_NACK;
m_rspType = PDU_ACK_TYPE_NACK_ILLEGAL;
m_rspStatus = 0U;
m_mfId = P25_MFG_STANDARD;
m_llId = 0U;
m_srcLlId = 0U;
m_extended = true;
m_blocksToFollow = 0U;
m_dataOctets = 0U;
}
/// <summary>Gets the total number of data octets.</summary>
/// <returns></returns>
uint32_t DataRspHeader::getDataOctets() const
{
return m_dataOctets;
}
/** Common Data */
/// <summary>Sets the total number of blocks to follow this header.</summary>
/// <param name="blocksToFollow"></param>
void DataRspHeader::setBlocksToFollow(uint8_t blocksToFollow)
{
m_blocksToFollow = blocksToFollow;
// recalculate count of data octets
m_dataOctets = 16 * m_blocksToFollow - 4;
}
/// <summary>Gets the total number of blocks to follow this header.</summary>
/// <returns></returns>
uint8_t DataRspHeader::getBlocksToFollow() const
{
return m_blocksToFollow;
}

@ -1,94 +0,0 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
/*
* Copyright (C) 2020 by Bryan Biedenkapp N2PLL
*
* 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(__P25_DATA__DATA_RSP_HEADER_H__)
#define __P25_DATA__DATA_RSP_HEADER_H__
#include "Defines.h"
#include "p25/edac/Trellis.h"
#include <string>
namespace p25
{
namespace data
{
// ---------------------------------------------------------------------------
// Class Declaration
// Represents the data response header for PDU P25 packets.
// ---------------------------------------------------------------------------
class HOST_SW_API DataRspHeader {
public:
/// <summary>Initializes a new instance of the DataRspHeader class.</summary>
DataRspHeader();
/// <summary>Finalizes a instance of the DataRspHeader class.</summary>
~DataRspHeader();
/// <summary>Decodes P25 PDU data response header.</summary>
bool decode(const uint8_t* data);
/// <summary>Encodes P25 PDU data response header.</summary>
void encode(uint8_t* data);
/// <summary>Helper to reset data values to defaults.</summary>
void reset();
/// <summary>Gets the total number of data octets.</summary>
uint32_t getDataOctets() const;
/** Common Data */
/// <summary>Sets the total number of blocks to follow this header.</summary>
void setBlocksToFollow(uint8_t blocksToFollow);
/// <summary>Gets the total number of blocks to follow this header.</summary>
uint8_t getBlocksToFollow() const;
public:
/// <summary>Flag indicating if this is an outbound data packet.</summary>
__PROPERTY(bool, outbound, Outbound);
/// <summary>Response class.</summary>
__PROPERTY(uint8_t, rspClass, Class);
/// <summary>Response type.</summary>
__PROPERTY(uint8_t, rspType, Type);
/// <summary>Response status.</summary>
__PROPERTY(uint8_t, rspStatus, Status);
/// <summary>Manufacturer ID.</summary>
__PROPERTY(uint8_t, mfId, MFId);
/// <summary>Logical link ID.</summary>
__PROPERTY(uint32_t, llId, LLId);
/// <summary>Source Logical link ID.</summary>
__PROPERTY(uint32_t, srcLlId, SrcLLId);
/// <summary>Flag indicating whether or not this response packet is to extended addressing.</summary>
__PROPERTY(bool, extended, Extended);
private:
edac::Trellis m_trellis;
uint8_t m_blocksToFollow;
uint32_t m_dataOctets;
};
} // namespace data
} // namespace p25
#endif // __P25_DATA__DATA_RSP_HEADER_H__
Loading…
Cancel
Save

Powered by TurnKey Linux.