diff --git a/p25/DataPacket.cpp b/p25/DataPacket.cpp
index cd4166fe..0ef94454 100644
--- a/p25/DataPacket.cpp
+++ b/p25/DataPacket.cpp
@@ -302,6 +302,17 @@ bool DataPacket::process(uint8_t* data, uint32_t len)
}
}
break;
+ case PDU_SAP_TRUNK_CTRL:
+ {
+ for (uint32_t i = 0; i < blocksToFollow; i++) {
+ uint8_t data[P25_TSBK_FEC_LENGTH_BYTES + 2U];
+ ::memset(data, 0x00U, P25_TSBK_FEC_LENGTH_BYTES + 2U);
+
+ uint32_t len = m_rfData[i].getData(data + 2U);
+ m_p25->m_trunk->process(data, len, true);
+ }
+ }
+ break;
default:
::ActivityLog("P25", true, "RF data transmission from %u to %u, %u blocks", m_rfDataHeader.getLLId(), m_rfDataHeader.getLLId(), m_rfDataHeader.getBlocksToFollow());
diff --git a/p25/P25Defines.h b/p25/P25Defines.h
index 766353ce..4225c6a9 100644
--- a/p25/P25Defines.h
+++ b/p25/P25Defines.h
@@ -210,6 +210,7 @@ namespace p25
const uint8_t PDU_FMT_RSP = 0x03U;
const uint8_t PDU_FMT_UNCONFIRMED = 0x15U;
const uint8_t PDU_FMT_CONFIRMED = 0x16U;
+ const uint8_t PDU_FMT_AMBT = 0x17U;
// PDU SAP
const uint8_t PDU_SAP_USER_DATA = 0x00U;
@@ -221,6 +222,7 @@ namespace p25
const uint8_t PDU_SAP_REG = 0x20U;
const uint8_t PDU_SAP_UNENC_KMM = 0x28U;
const uint8_t PDU_SAP_ENC_KMM = 0x29U;
+ const uint8_t PDU_SAP_TRUNK_CTRL = 0x3DU;
// PDU ACK Class
const uint8_t PDU_ACK_CLASS_ACK = 0x00U;
diff --git a/p25/TrunkPacket.cpp b/p25/TrunkPacket.cpp
index f76d5179..36af0dab 100644
--- a/p25/TrunkPacket.cpp
+++ b/p25/TrunkPacket.cpp
@@ -157,23 +157,30 @@ void TrunkPacket::resetNet()
///
/// Buffer containing data frame.
/// Length of data frame.
+/// Flag indicating the data parameter contains MBT data.
///
-bool TrunkPacket::process(uint8_t* data, uint32_t len)
+bool TrunkPacket::process(uint8_t* data, uint32_t len, bool mbtData)
{
assert(data != NULL);
if (!m_p25->m_control)
return false;
- // Decode the NID
- bool valid = m_p25->m_nid.decode(data + 2U);
+ uint8_t duid = 0U;
+ if (!mbtData) {
+ // Decode the NID
+ bool valid = m_p25->m_nid.decode(data + 2U);
- if (m_p25->m_rfState == RS_RF_LISTENING && !valid)
- return false;
+ if (m_p25->m_rfState == RS_RF_LISTENING && !valid)
+ return false;
- RPT_RF_STATE prevRfState = m_p25->m_rfState;
- uint8_t duid = m_p25->m_nid.getDUID();
+ duid = m_p25->m_nid.getDUID();
+ } else {
+ duid = P25_DUID_TSDU;
+ }
+ RPT_RF_STATE prevRfState = m_p25->m_rfState;
+
// handle individual DUIDs
if (duid == P25_DUID_TSDU) {
if (m_p25->m_rfState != RS_RF_DATA) {
diff --git a/p25/TrunkPacket.h b/p25/TrunkPacket.h
index aa8ac381..7bbb31e7 100644
--- a/p25/TrunkPacket.h
+++ b/p25/TrunkPacket.h
@@ -61,7 +61,7 @@ namespace p25
void resetNet();
/// Process a data frame from the RF interface.
- bool process(uint8_t* data, uint32_t len);
+ bool process(uint8_t* data, uint32_t len, bool mbtData = false);
/// Process a data frame from the network.
bool processNetwork(uint8_t* data, uint32_t len, lc::LC& control, data::LowSpeedData& lsd, uint8_t& duid);
diff --git a/p25/data/DataHeader.cpp b/p25/data/DataHeader.cpp
index e111210d..30e13d4a 100644
--- a/p25/data/DataHeader.cpp
+++ b/p25/data/DataHeader.cpp
@@ -54,6 +54,7 @@ DataHeader::DataHeader() :
m_n(0U),
m_seqNo(0U),
m_headerOffset(0U),
+ m_ambtOpcode(0U),
m_trellis(),
m_blocksToFollow(0U),
m_padCount(0U),
@@ -103,8 +104,15 @@ bool DataHeader::decode(const uint8_t* data)
m_llId = (header[3U] << 16) + (header[4U] << 8) + header[5U]; // Logical Link ID
m_fullMessage = (header[6U] & 0x80U) == 0x80U; // Full Message Flag
+
m_blocksToFollow = header[6U] & 0x7FU; // Block Frames to Follow
- m_padCount = header[7U] & 0x1FU; // Pad Count
+ if (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) {
m_dataOctets = 16 * m_blocksToFollow - 4 - m_padCount;
@@ -150,7 +158,12 @@ void DataHeader::encode(uint8_t* data)
header[6U] = (m_fullMessage ? 0x80U : 0x00U) + // Full Message Flag
(m_blocksToFollow & 0x7FU); // Blocks Frames to Follow
- header[7U] = (m_padCount & 0x1FU); // Pad Count
+ if (m_fmt == PDU_FMT_AMBT) {
+ header[7U] = (m_ambtOpcode & 0x3FU); // AMBT Opcode
+ }
+ else {
+ header[7U] = (m_padCount & 0x1FU); // Pad Count
+ }
header[8U] = (m_sync ? 0x80U : 0x00U) + // Re-synchronize Flag
((m_n << 4) && 0x07U) + // Packet Sequence No.
@@ -191,6 +204,7 @@ void DataHeader::reset()
m_seqNo = 0U;
m_headerOffset = 0U;
+ m_ambtOpcode = 0U;
}
/// Gets the total number of data octets.
diff --git a/p25/data/DataHeader.h b/p25/data/DataHeader.h
index 57f5a231..084e94bf 100644
--- a/p25/data/DataHeader.h
+++ b/p25/data/DataHeader.h
@@ -91,6 +91,8 @@ namespace p25
__PROPERTY(uint8_t, seqNo, SeqNo);
/// Offset of the header.
__PROPERTY(uint8_t, headerOffset, HeaderOffset);
+ /// Alternate Trunking Block Opcode
+ __PROPERTY(uint8_t, ambtOpcode, AMBTOpcode);
private:
edac::Trellis m_trellis;