diff --git a/DVMHost.vcxproj b/DVMHost.vcxproj
index 24635be7..11a50ad2 100644
--- a/DVMHost.vcxproj
+++ b/DVMHost.vcxproj
@@ -210,7 +210,6 @@
-
@@ -290,7 +289,6 @@
-
diff --git a/DVMHost.vcxproj.filters b/DVMHost.vcxproj.filters
index 8feda304..5917e50d 100644
--- a/DVMHost.vcxproj.filters
+++ b/DVMHost.vcxproj.filters
@@ -338,9 +338,6 @@
Header Files\network
-
- Header Files\p25\data
-
Header Files\dmr
@@ -568,9 +565,6 @@
Source Files\network
-
- Source Files\p25\data
-
Source Files\dmr
diff --git a/Makefile b/Makefile
index 642ce6f4..230af041 100644
--- a/Makefile
+++ b/Makefile
@@ -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 \
diff --git a/Makefile.arm b/Makefile.arm
index 4f00fbf5..9d114099 100644
--- a/Makefile.arm
+++ b/Makefile.arm
@@ -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 \
diff --git a/Makefile.rpi-arm b/Makefile.rpi-arm
index 6b5bb3fd..0c7bfb1a 100644
--- a/Makefile.rpi-arm
+++ b/Makefile.rpi-arm
@@ -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 \
diff --git a/edac/CRC.cpp b/edac/CRC.cpp
index 294ba855..905da1e0 100644
--- a/edac/CRC.cpp
+++ b/edac/CRC.cpp
@@ -449,15 +449,15 @@ uint8_t CRC::crc8(const uint8_t *in, uint32_t length)
/// Generate 9-bit CRC.
///
/// Input byte array.
-/// Length of byte array in bits.
+/// Length of byte array in bits.
/// Calculated 9-bit CRC value.
-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;
diff --git a/edac/CRC.h b/edac/CRC.h
index af8dfe50..660f0c5a 100644
--- a/edac/CRC.h
+++ b/edac/CRC.h
@@ -66,7 +66,7 @@ namespace edac
static uint8_t crc8(const uint8_t* in, uint32_t length);
/// Generate 9-bit CRC.
- static uint16_t crc9(const uint8_t* in, uint32_t bitlen);
+ static uint16_t crc9(const uint8_t* in, uint32_t bitLength);
};
} // namespace edac
diff --git a/host/calibrate/HostCal.cpp b/host/calibrate/HostCal.cpp
index 780c0e5e..4036369b 100644
--- a/host/calibrate/HostCal.cpp
+++ b/host/calibrate/HostCal.cpp
@@ -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;
diff --git a/p25/DataPacket.cpp b/p25/DataPacket.cpp
index 7c6da2e8..65948bd0 100644
--- a/p25/DataPacket.cpp
+++ b/p25/DataPacket.cpp
@@ -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
///
/// Helper to write a P25 PDU packet.
///
-void DataPacket::writeRF_PDU()
+///
+///
+///
+/// This simply takes data packed into m_rfPDU and transmits it.
+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();
+ }
+}
+
+///
+/// Helper to re-write a received P25 PDU packet.
+///
+/// This will take buffered received PDU data and repeat it over the air.
+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);
}
///
@@ -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);
}
///
@@ -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);
}
///
@@ -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());
}
diff --git a/p25/DataPacket.h b/p25/DataPacket.h
index 47e839d3..0f350d24 100644
--- a/p25/DataPacket.h
+++ b/p25/DataPacket.h
@@ -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);
/// Helper to write a P25 PDU packet.
- void writeRF_PDU();
+ void writeRF_PDU(const uint8_t* pdu, uint32_t bitLength, bool noNulls = false);
+ /// Helper to re-write a received P25 PDU packet.
+ void writeRF_PDU_Buffered();
/// Helper to write a PDU registration response.
void writeRF_PDU_Reg_Response(uint8_t regType, uint32_t llId, ulong64_t ipAddr);
/// Helper to write a PDU acknowledge response.
diff --git a/p25/data/DataBlock.h b/p25/data/DataBlock.h
index 7a00582d..da1b09bb 100644
--- a/p25/data/DataBlock.h
+++ b/p25/data/DataBlock.h
@@ -74,6 +74,7 @@ namespace p25
/// Flag indicating this is the last block in a sequence of block.
__PROPERTY(bool, lastBlock, LastBlock);
+
/// Logical link ID.
__PROPERTY(uint32_t, llId, LLId);
/// Service access point.
diff --git a/p25/data/DataHeader.cpp b/p25/data/DataHeader.cpp
index 3f27ac72..f0232c84 100644
--- a/p25/data/DataHeader.cpp
+++ b/p25/data/DataHeader.cpp
@@ -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;
}
/// Gets the total number of data octets.
diff --git a/p25/data/DataHeader.h b/p25/data/DataHeader.h
index 4e05eab6..408e2eea 100644
--- a/p25/data/DataHeader.h
+++ b/p25/data/DataHeader.h
@@ -82,16 +82,30 @@ namespace p25
/// Logical link ID.
__PROPERTY(uint32_t, llId, LLId);
/// Flag indicating whether or not this data packet is a full message.
- __PROPERTY(bool, fullMessage, FullMessage);
- ///
- __PROPERTY(bool, sync, Sync);
- ///
- __PROPERTY(uint8_t, n, N);
- /// Data packet sequence number.
- __PROPERTY(uint8_t, seqNo, SeqNo);
+ /// When a response header, this represents the extended flag.
+ __PROPERTY(bool, F, FullMessage);
+ /// Synchronize Flag.
+ __PROPERTY(bool, S, Synchronize);
+ /// Fragment Sequence Number.
+ __PROPERTY(uint8_t, fsn, FSN);
+ /// Send Sequence Number.
+ __PROPERTY(uint8_t, Ns, Ns);
+ /// Flag indicating whether or not this is the last fragment in a message.
+ __PROPERTY(bool, lastFragment, LastFragment);
/// Offset of the header.
__PROPERTY(uint8_t, headerOffset, HeaderOffset);
+ /** Response Data */
+ /// Source Logical link ID.
+ __PROPERTY(uint32_t, srcLlId, SrcLLId);
+ /// Response class.
+ __PROPERTY(uint8_t, rspClass, Class);
+ /// Response type.
+ __PROPERTY(uint8_t, rspType, Type);
+ /// Response status.
+ __PROPERTY(uint8_t, rspStatus, Status);
+
+ /** AMBT Data */
/// Alternate Trunking Block Opcode
__PROPERTY(uint8_t, ambtOpcode, AMBTOpcode);
/// Alternate Trunking Block Field 8
diff --git a/p25/data/DataRspHeader.cpp b/p25/data/DataRspHeader.cpp
deleted file mode 100644
index bac1e79d..00000000
--- a/p25/data/DataRspHeader.cpp
+++ /dev/null
@@ -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
-#include
-#include
-
-// ---------------------------------------------------------------------------
-// Public Class Members
-// ---------------------------------------------------------------------------
-///
-/// Initializes a new instance of the DataRspHeader class.
-///
-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 */
-}
-
-///
-/// Finalizes a instance of the DataRspHeader class.
-///
-DataRspHeader::~DataRspHeader()
-{
- /* stub */
-}
-
-///
-/// Decodes P25 PDU data response header.
-///
-///
-/// True, if PDU data response header was decoded, otherwise false.
-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;
-}
-
-///
-/// Encodes P25 PDU data response header.
-///
-///
-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);
-}
-
-///
-/// Helper to reset data values to defaults.
-///
-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;
-}
-
-/// Gets the total number of data octets.
-///
-uint32_t DataRspHeader::getDataOctets() const
-{
- return m_dataOctets;
-}
-
-/** Common Data */
-/// Sets the total number of blocks to follow this header.
-///
-void DataRspHeader::setBlocksToFollow(uint8_t blocksToFollow)
-{
- m_blocksToFollow = blocksToFollow;
-
- // recalculate count of data octets
- m_dataOctets = 16 * m_blocksToFollow - 4;
-}
-
-/// Gets the total number of blocks to follow this header.
-///
-uint8_t DataRspHeader::getBlocksToFollow() const
-{
- return m_blocksToFollow;
-}
diff --git a/p25/data/DataRspHeader.h b/p25/data/DataRspHeader.h
deleted file mode 100644
index 76ba4215..00000000
--- a/p25/data/DataRspHeader.h
+++ /dev/null
@@ -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
-
-namespace p25
-{
- namespace data
- {
- // ---------------------------------------------------------------------------
- // Class Declaration
- // Represents the data response header for PDU P25 packets.
- // ---------------------------------------------------------------------------
-
- class HOST_SW_API DataRspHeader {
- public:
- /// Initializes a new instance of the DataRspHeader class.
- DataRspHeader();
- /// Finalizes a instance of the DataRspHeader class.
- ~DataRspHeader();
-
- /// Decodes P25 PDU data response header.
- bool decode(const uint8_t* data);
- /// Encodes P25 PDU data response header.
- void encode(uint8_t* data);
-
- /// Helper to reset data values to defaults.
- void reset();
-
- /// Gets the total number of data octets.
- uint32_t getDataOctets() const;
-
- /** Common Data */
- /// Sets the total number of blocks to follow this header.
- void setBlocksToFollow(uint8_t blocksToFollow);
- /// Gets the total number of blocks to follow this header.
- uint8_t getBlocksToFollow() const;
-
- public:
- /// Flag indicating if this is an outbound data packet.
- __PROPERTY(bool, outbound, Outbound);
- /// Response class.
- __PROPERTY(uint8_t, rspClass, Class);
- /// Response type.
- __PROPERTY(uint8_t, rspType, Type);
- /// Response status.
- __PROPERTY(uint8_t, rspStatus, Status);
- /// Manufacturer ID.
- __PROPERTY(uint8_t, mfId, MFId);
- /// Logical link ID.
- __PROPERTY(uint32_t, llId, LLId);
- /// Source Logical link ID.
- __PROPERTY(uint32_t, srcLlId, SrcLLId);
- /// Flag indicating whether or not this response packet is to extended addressing.
- __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__