diff --git a/src/dmr/Slot.cpp b/src/dmr/Slot.cpp
index 7b7099a1..9f838b2b 100644
--- a/src/dmr/Slot.cpp
+++ b/src/dmr/Slot.cpp
@@ -509,9 +509,6 @@ void Slot::clock()
}
}
}
- else {
- clearTSCCActivated();
- }
}
// handle timeouts and hang timers
@@ -1429,6 +1426,10 @@ void Slot::writeRF_ControlData(uint16_t frameCnt, uint8_t n)
///
void Slot::clearTSCCActivated()
{
+ if (m_tsccPayloadDstId != 0U && m_tsccPayloadSrcId != 0U) {
+ m_control->writeRF_CSBK_Payload_Clear(m_tsccPayloadDstId, m_tsccPayloadSrcId, m_tsccPayloadGroup);
+ }
+
m_tsccPayloadDstId = 0U;
m_tsccPayloadSrcId = 0U;
m_tsccPayloadGroup = false;
diff --git a/src/dmr/lc/CSBK.h b/src/dmr/lc/CSBK.h
index e584ead7..fdab303d 100644
--- a/src/dmr/lc/CSBK.h
+++ b/src/dmr/lc/CSBK.h
@@ -82,7 +82,7 @@ namespace dmr
/// DMR access color code.
__PROTECTED_PROPERTY(uint8_t, colorCode, ColorCode);
- /// Flag indicating this is the last TSBK in a sequence of TSBKs.
+ /// Flag indicating this is the last CSBK in a sequence of CSBKs.
__PROTECTED_PROPERTY(bool, lastBlock, LastBlock);
/// Flag indicating whether the CSBK is a Cdef block.
__PROTECTED_PROPERTY(bool, Cdef, Cdef);
diff --git a/src/dmr/packet/ControlSignaling.cpp b/src/dmr/packet/ControlSignaling.cpp
index 50a69815..a53eb86f 100644
--- a/src/dmr/packet/ControlSignaling.cpp
+++ b/src/dmr/packet/ControlSignaling.cpp
@@ -1367,7 +1367,7 @@ void ControlSignaling::writeRF_CSBK_Grant_LateEntry(uint32_t dstId, uint32_t src
}
///
-/// Helper to write a payload random access to a TSCC payload channel on the RF interface.
+/// Helper to write a payload activation to a TSCC payload channel on the RF interface.
///
///
///
@@ -1412,6 +1412,36 @@ void ControlSignaling::writeRF_CSBK_Payload_Activate(uint32_t dstId, uint32_t sr
writeRF_CSBK(csbk.get(), false, imm);
}
+///
+/// Helper to write a payload clear to a TSCC payload channel on the RF interface.
+///
+///
+///
+///
+///
+void ControlSignaling::writeRF_CSBK_Payload_Clear(uint32_t dstId, uint32_t srcId, bool grp, bool imm)
+{
+ std::unique_ptr csbk = new_unique(CSBK_P_CLEAR);
+
+ csbk->setGI(grp);
+
+ csbk->setLastBlock(true);
+
+ csbk->setLogicalCh1(m_slot->m_channelNo);
+ csbk->setSlotNo(m_slot->m_slotNo);
+
+ csbk->setSrcId(srcId);
+ csbk->setDstId(dstId);
+
+ if (m_verbose) {
+ LogMessage(LOG_RF, "DMR Slot %u, DT_CSBK, %s, group = %u, chNo = %u, slot = %u, srcId = %u, dstId = %u",
+ m_slot->m_slotNo, csbk->toString().c_str(), csbk->getGI(), csbk->getLogicalCh1(), csbk->getSlotNo(), srcId, dstId);
+ }
+
+ for (uint8_t i = 0; i < 2U; i++)
+ writeRF_CSBK(csbk.get(), false, imm);
+}
+
///
/// Helper to write a TSCC Aloha broadcast packet on the RF interface.
///
diff --git a/src/dmr/packet/ControlSignaling.h b/src/dmr/packet/ControlSignaling.h
index bd9f1bbc..13c35fb0 100644
--- a/src/dmr/packet/ControlSignaling.h
+++ b/src/dmr/packet/ControlSignaling.h
@@ -111,8 +111,10 @@ namespace dmr
/// Helper to write a TSCC late entry channel grant packet on the RF interface.
void writeRF_CSBK_Grant_LateEntry(uint32_t dstId, uint32_t srcId, bool grp);
- /// Helper to write a payload random access to a TSCC payload channel on the RF interface.
+ /// Helper to write a payload activation to a TSCC payload channel on the RF interface.
void writeRF_CSBK_Payload_Activate(uint32_t dstId, uint32_t srcId, bool grp, bool voice, bool imm = false);
+ /// Helper to write a payload clear to a TSCC payload channel on the RF interface.
+ void writeRF_CSBK_Payload_Clear(uint32_t dstId, uint32_t srcId, bool grp, bool imm = false);
/// Helper to write a TSCC Aloha broadcast packet on the RF interface.
void writeRF_TSCC_Aloha();
diff --git a/src/dmr/packet/Data.cpp b/src/dmr/packet/Data.cpp
index 75834629..c7bdc355 100644
--- a/src/dmr/packet/Data.cpp
+++ b/src/dmr/packet/Data.cpp
@@ -141,6 +141,7 @@ bool Data::process(uint8_t* data, uint32_t len)
if (m_tscc != nullptr) {
if (m_tscc->m_enableTSCC) {
m_tscc->m_affiliations->releaseGrant(m_slot->m_rfLC->getDstId(), false);
+ m_slot->clearTSCCActivated();
}
}
@@ -382,6 +383,15 @@ void Data::processNetwork(const data::Data& dmrData)
LogMessage(LOG_RF, DMR_DT_TERMINATOR_WITH_LC ", slot = %u, dstId = %u", m_slot->m_slotNo, m_slot->m_netLC->getDstId());
}
+ // release trunked grant (if necessary)
+ Slot *m_tscc = m_slot->m_dmr->getTSCCSlot();
+ if (m_tscc != nullptr) {
+ if (m_tscc->m_enableTSCC) {
+ m_tscc->m_affiliations->releaseGrant(m_slot->m_rfLC->getDstId(), false);
+ m_slot->clearTSCCActivated();
+ }
+ }
+
// We've received the voice header and terminator haven't we?
m_slot->m_netFrames += 2U;
::ActivityLog("DMR", false, "Slot %u network end of voice transmission, %.1f seconds, %u%% packet loss, BER: %.1f%%",