diff --git a/p25/lc/TSBK.cpp b/p25/lc/TSBK.cpp
index 69bbc647..9200bc10 100644
--- a/p25/lc/TSBK.cpp
+++ b/p25/lc/TSBK.cpp
@@ -334,13 +334,10 @@ bool TSBK::decodeMBT(const data::DataHeader dataHeader, const data::DataBlock* b
/// Encode a alternate trunking signalling block.
///
///
-///
-void TSBK::encodeMBT(data::DataHeader& dataHeader, data::DataBlock* blocks)
+///
+void TSBK::encodeMBT(data::DataHeader& dataHeader, uint8_t* pduUserData)
{
- assert(blocks != NULL);
-
- uint8_t pduUserData[P25_PDU_UNCONFIRMED_LENGTH_BYTES * 2U];
- ::memset(pduUserData, 0x00U, P25_PDU_UNCONFIRMED_LENGTH_BYTES * 2U);
+ assert(pduUserData != NULL);
dataHeader.setFormat(PDU_FMT_UNCONFIRMED);
dataHeader.setMFId(m_mfId);
@@ -394,15 +391,8 @@ void TSBK::encodeMBT(data::DataHeader& dataHeader, data::DataBlock* blocks)
// generate packet CRC-32 and set data blocks
if (dataHeader.getBlocksToFollow() > 1U) {
edac::CRC::addCRC32(pduUserData, P25_PDU_UNCONFIRMED_LENGTH_BYTES * dataHeader.getBlocksToFollow());
-
- uint8_t offs = 0U;
- for (uint8_t i = 0; i < dataHeader.getBlocksToFollow(); i++) {
- blocks[i].setData(pduUserData + offs);
- offs += P25_PDU_UNCONFIRMED_LENGTH_BYTES;
- }
} else {
edac::CRC::addCRC32(pduUserData, P25_PDU_UNCONFIRMED_LENGTH_BYTES);
- blocks[0U].setData(pduUserData);
}
}
diff --git a/p25/lc/TSBK.h b/p25/lc/TSBK.h
index c19f9297..d2680dba 100644
--- a/p25/lc/TSBK.h
+++ b/p25/lc/TSBK.h
@@ -84,7 +84,7 @@ namespace p25
/// Decode a alternate trunking signalling block.
bool decodeMBT(const data::DataHeader dataHeader, const data::DataBlock* blocks);
/// Encode a alternate trunking signalling block.
- void encodeMBT(data::DataHeader& dataHeader, data::DataBlock* blocks);
+ void encodeMBT(data::DataHeader& dataHeader, uint8_t* pduUserData);
/// Decode a trunking signalling block.
bool decode(const uint8_t* data, bool rawTSBK = false);
diff --git a/p25/packet/Data.h b/p25/packet/Data.h
index 193fdfe0..d959b595 100644
--- a/p25/packet/Data.h
+++ b/p25/packet/Data.h
@@ -51,6 +51,7 @@ namespace p25
// ---------------------------------------------------------------------------
class HOST_SW_API Control;
+ namespace packet { class HOST_SW_API Trunk; }
namespace packet
{
@@ -78,6 +79,7 @@ namespace p25
private:
friend class p25::Control;
Control* m_p25;
+ friend class p25::packet::Trunk;
network::BaseNetwork* m_network;
diff --git a/p25/packet/Trunk.cpp b/p25/packet/Trunk.cpp
index 82a94f6d..8527f6c6 100644
--- a/p25/packet/Trunk.cpp
+++ b/p25/packet/Trunk.cpp
@@ -1666,6 +1666,67 @@ void Trunk::writeRF_TSDU_MBF(bool clearBeforeWrite)
m_mbfCnt++;
}
+///
+/// Helper to write a alternate multi-block trunking PDU packet.
+///
+///
+void Trunk::writeRF_PDU_AMBT(bool clearBeforeWrite)
+{
+ if (!m_p25->m_control)
+ return;
+
+ DataHeader rspHeader = DataHeader();
+ uint8_t rspData[P25_PDU_UNCONFIRMED_LENGTH_BYTES * P25_MAX_PDU_COUNT];
+ ::memset(rspData, 0x00U, P25_PDU_UNCONFIRMED_LENGTH_BYTES * P25_MAX_PDU_COUNT);
+
+ // Generate TSBK block
+ m_rfTSBK.setLastBlock(true); // always set last block -- this a Single Block TSDU
+ m_rfTSBK.encodeMBT(rspHeader, rspData);
+
+ if (m_debug) {
+ LogDebug(LOG_RF, P25_PDU_STR " AMBT, lco = $%02X, mfId = $%02X, lastBlock = %u, AIV = %u, EX = %u, srcId = %u, dstId = %u, sysId = $%03X, netId = $%05X",
+ m_rfTSBK.getLCO(), m_rfTSBK.getMFId(), m_rfTSBK.getLastBlock(), m_rfTSBK.getAIV(), m_rfTSBK.getEX(), m_rfTSBK.getSrcId(), m_rfTSBK.getDstId(),
+ m_rfTSBK.getSysId(), m_rfTSBK.getNetId());
+
+ Utils::dump(1U, "!!! *TSDU (AMBT) TSBK Block Data", rspData, P25_PDU_UNCONFIRMED_LENGTH_BYTES * rspHeader.getBlocksToFollow());
+ }
+
+ uint32_t bitLength = ((rspHeader.getBlocksToFollow() + 1U) * P25_PDU_FEC_LENGTH_BITS) + P25_PREAMBLE_LENGTH_BITS;
+ uint32_t offset = P25_PREAMBLE_LENGTH_BITS;
+
+ 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);
+
+ // Generate the PDU header and 1/2 rate Trellis
+ rspHeader.encode(block);
+ Utils::setBitRange(block, data, offset, P25_PDU_FEC_LENGTH_BITS);
+ offset += P25_PDU_FEC_LENGTH_BITS;
+
+ // Generate the PDU data
+ DataBlock rspBlock = DataBlock();
+ uint8_t offs = 0U;
+ for (uint8_t i = 0; i < rspHeader.getBlocksToFollow(); i++) {
+ rspBlock.setFormat(PDU_FMT_UNCONFIRMED);
+ rspBlock.setSerialNo(0U);
+ rspBlock.setData(rspData + offs);
+
+ ::memset(block, 0x00U, P25_PDU_FEC_LENGTH_BYTES);
+ rspBlock.encode(block);
+ Utils::setBitRange(block, data, offset, P25_PDU_FEC_LENGTH_BITS);
+ offset += P25_PDU_FEC_LENGTH_BITS;
+ offs += P25_PDU_UNCONFIRMED_LENGTH_BYTES;
+ }
+
+ if (clearBeforeWrite) {
+ m_p25->m_modem->clearP25Data();
+ m_p25->m_queue.clear();
+ }
+
+ m_p25->m_data->writeRF_PDU(data, bitLength);
+}
+
///
/// Helper to generate the given control TSBK into the TSDU frame queue.
///
diff --git a/p25/packet/Trunk.h b/p25/packet/Trunk.h
index f1485564..31498fe3 100644
--- a/p25/packet/Trunk.h
+++ b/p25/packet/Trunk.h
@@ -178,6 +178,8 @@ namespace p25
virtual void writeRF_TSDU_SBF(bool noNetwork, bool clearBeforeWrite = false, bool force = false);
/// Helper to write a multi-block (3-block) P25 TSDU packet.
void writeRF_TSDU_MBF(bool clearBeforeWrite = false);
+ /// Helper to write a alternate multi-block trunking PDU packet.
+ void writeRF_PDU_AMBT(bool clearBeforeWrite = false);
/// Helper to generate the given control TSBK into the TSDU frame queue.
void queueRF_TSBK_Ctrl(uint8_t lco);