From 7e2e002b102f6f268ae5a0751744e8cf266d1ea7 Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Fri, 24 Mar 2023 20:19:51 -0400 Subject: [PATCH] add appropriate support for DMR TSCC to repeat the channel grant following appropriate channel grant; add support to affiliation tables to log what source ID a destination ID is granted to; --- src/dmr/Slot.cpp | 38 ++++++++++++++++++++++-- src/dmr/Slot.h | 2 ++ src/dmr/lc/csbk/CSBK_TV_GRANT.cpp | 20 +++++++++++-- src/dmr/lc/csbk/CSBK_TV_GRANT.h | 6 ++++ src/dmr/lookups/DMRAffiliationLookup.cpp | 12 +++++--- src/dmr/lookups/DMRAffiliationLookup.h | 4 +-- src/dmr/packet/ControlSignaling.cpp | 27 +++++++++++++++-- src/dmr/packet/ControlSignaling.h | 3 ++ src/lookups/AffiliationLookup.cpp | 31 ++++++++++++++++--- src/lookups/AffiliationLookup.h | 5 +++- src/nxdn/packet/Trunk.cpp | 2 +- src/p25/packet/Trunk.cpp | 4 +-- 12 files changed, 133 insertions(+), 21 deletions(-) diff --git a/src/dmr/Slot.cpp b/src/dmr/Slot.cpp index 464a7248..f2d75525 100644 --- a/src/dmr/Slot.cpp +++ b/src/dmr/Slot.cpp @@ -159,6 +159,7 @@ Slot::Slot(uint32_t slotNo, uint32_t timeout, uint32_t tgHang, uint32_t queueSiz m_tsccPayloadDstId(0U), m_tsccPayloadGroup(false), m_tsccPayloadVoice(true), + m_lastLateEntry(0U), m_verbose(verbose), m_debug(debug) { @@ -438,7 +439,7 @@ void Slot::clock() if (m_ccPacketInterval.isRunning() && m_ccPacketInterval.hasExpired()) { if (m_ccRunning) { - if (m_ccSeq == 3U) { + if (m_ccSeq == 4U) { m_ccSeq = 0U; } @@ -975,9 +976,9 @@ void Slot::writeRF_ControlData(uint16_t frameCnt, uint8_t n) return; } - // loop to generate 3 control sequences + // loop to generate 4 control sequences if (frameCnt == 511U) { - seqCnt = 3U; + seqCnt = 4U; } // should we insert the Git Hash burst? @@ -999,6 +1000,37 @@ void Slot::writeRF_ControlData(uint16_t frameCnt, uint8_t n) switch (n) { + case 3: + { + std::unordered_map grants = m_affiliations->grantTable(); + if (grants.size() > 0) { + uint32_t j = 0U; + if (m_lastLateEntry > grants.size()) { + m_lastLateEntry = 0U; + } + + for (auto entry : grants) { + if (j == m_lastLateEntry) { + uint32_t dstId = entry.first; + uint32_t srcId = m_affiliations->getGrantedSrcId(dstId); + + if (m_debug) { + LogDebug(LOG_DMR, "writeRF_ControlData, frameCnt = %u, seq = %u, late entry, dstId = %u, srcId = %u", frameCnt, n, dstId, srcId); + } + + m_control->writeRF_CSBK_Grant_LateEntry(dstId, srcId); + m_lastLateEntry = j++; + break; + } + + j++; + } + } + else { + m_control->writeRF_TSCC_Bcast_Sys_Parm(); + } + } + break; case 2: m_control->writeRF_TSCC_Bcast_Ann_Wd(m_channelNo, true); break; diff --git a/src/dmr/Slot.h b/src/dmr/Slot.h index 44298283..d98b58aa 100644 --- a/src/dmr/Slot.h +++ b/src/dmr/Slot.h @@ -196,6 +196,8 @@ namespace dmr bool m_tsccPayloadGroup; bool m_tsccPayloadVoice; + uint32_t m_lastLateEntry; + bool m_controlPermitTG; bool m_verbose; diff --git a/src/dmr/lc/csbk/CSBK_TV_GRANT.cpp b/src/dmr/lc/csbk/CSBK_TV_GRANT.cpp index 9ecc94a4..d54957f5 100644 --- a/src/dmr/lc/csbk/CSBK_TV_GRANT.cpp +++ b/src/dmr/lc/csbk/CSBK_TV_GRANT.cpp @@ -42,7 +42,8 @@ using namespace dmr; /// /// Initializes a new instance of the CSBK_TV_GRANT class. /// -CSBK_TV_GRANT::CSBK_TV_GRANT() : CSBK() +CSBK_TV_GRANT::CSBK_TV_GRANT() : CSBK(), + m_lateEntry(false) { m_CSBKO = CSBKO_TV_GRANT; } @@ -73,7 +74,7 @@ void CSBK_TV_GRANT::encode(uint8_t* data) csbkValue = (csbkValue << 12) + (m_logicalCh1 & 0xFFFU); // Logical Physical Channel 1 csbkValue = (csbkValue << 1) + (m_slotNo & 0x3U); // Logical Slot Number - csbkValue = (csbkValue << 1) + 0U; // Late Entry + csbkValue = (csbkValue << 1) + ((m_lateEntry) ? 1U : 0U);; // Late Entry csbkValue = (csbkValue << 1) + ((m_emergency) ? 1U : 0U); // Emergency csbkValue = (csbkValue << 1) + ((m_siteOffsetTiming) ? 1U : 0U); // Site Timing: Aligned or Offset csbkValue = (csbkValue << 24) + m_dstId; // Talkgroup ID @@ -82,3 +83,18 @@ void CSBK_TV_GRANT::encode(uint8_t* data) std::unique_ptr csbk = CSBK::fromValue(csbkValue); CSBK::encode(data, csbk.get()); } + +// --------------------------------------------------------------------------- +// Private Class Members +// --------------------------------------------------------------------------- + +/// +/// Internal helper to copy the the class. +/// +/// +void CSBK_TV_GRANT::copy(const CSBK_TV_GRANT& data) +{ + CSBK::copy(data); + + m_lateEntry = data.m_lateEntry; +} diff --git a/src/dmr/lc/csbk/CSBK_TV_GRANT.h b/src/dmr/lc/csbk/CSBK_TV_GRANT.h index 2ae4f57e..03659df6 100644 --- a/src/dmr/lc/csbk/CSBK_TV_GRANT.h +++ b/src/dmr/lc/csbk/CSBK_TV_GRANT.h @@ -49,6 +49,12 @@ namespace dmr virtual bool decode(const uint8_t* data); /// Encode a control signalling block. virtual void encode(uint8_t* data); + + public: + /// Flag indicating whether the grant is a late entry. + __PROPERTY(bool, lateEntry, LateEntry); + + __COPY(CSBK_TV_GRANT); }; } // namespace csbk } // namespace lc diff --git a/src/dmr/lookups/DMRAffiliationLookup.cpp b/src/dmr/lookups/DMRAffiliationLookup.cpp index d5d28375..21e8b19b 100644 --- a/src/dmr/lookups/DMRAffiliationLookup.cpp +++ b/src/dmr/lookups/DMRAffiliationLookup.cpp @@ -62,9 +62,10 @@ DMRAffiliationLookup::~DMRAffiliationLookup() /// Helper to grant a channel. /// /// +/// /// /// -bool DMRAffiliationLookup::grantCh(uint32_t dstId, uint32_t grantTimeout) +bool DMRAffiliationLookup::grantCh(uint32_t dstId, uint32_t srcId, uint32_t grantTimeout) { uint32_t chNo = m_rfChTable.at(0); uint8_t slot = getAvailableSlotForChannel(chNo); @@ -73,17 +74,18 @@ bool DMRAffiliationLookup::grantCh(uint32_t dstId, uint32_t grantTimeout) return false; } - return grantChSlot(dstId, slot, grantTimeout); + return grantChSlot(dstId, srcId, slot, grantTimeout); } /// /// Helper to grant a channel and slot. /// /// +/// /// /// /// -bool DMRAffiliationLookup::grantChSlot(uint32_t dstId, uint8_t slot, uint32_t grantTimeout) +bool DMRAffiliationLookup::grantChSlot(uint32_t dstId, uint32_t srcId, uint8_t slot, uint32_t grantTimeout) { if (dstId == 0U) { return false; @@ -104,6 +106,7 @@ bool DMRAffiliationLookup::grantChSlot(uint32_t dstId, uint8_t slot, uint32_t gr } m_grantChTable[dstId] = chNo; + m_grantSrcIdTable[dstId] = srcId; m_grantChSlotTable[dstId] = std::make_tuple(chNo, slot); m_rfGrantChCnt++; @@ -161,7 +164,8 @@ bool DMRAffiliationLookup::releaseGrant(uint32_t dstId, bool releaseAll) m_releaseGrant(chNo, dstId, slot); } - m_grantChTable[dstId] = 0U; + m_grantChTable.erase(dstId); + m_grantSrcIdTable.erase(dstId); m_grantChSlotTable.erase(dstId); auto it = std::find(m_rfChTable.begin(), m_rfChTable.end(), chNo); diff --git a/src/dmr/lookups/DMRAffiliationLookup.h b/src/dmr/lookups/DMRAffiliationLookup.h index 19eedb5a..ab784dc2 100644 --- a/src/dmr/lookups/DMRAffiliationLookup.h +++ b/src/dmr/lookups/DMRAffiliationLookup.h @@ -50,9 +50,9 @@ namespace dmr virtual ~DMRAffiliationLookup(); /// Helper to grant a channel. - virtual bool grantCh(uint32_t dstId, uint32_t grantTimeout); + virtual bool grantCh(uint32_t dstId, uint32_t srcId, uint32_t grantTimeout); /// Helper to grant a channel and slot. - bool grantChSlot(uint32_t dstId, uint8_t slot, uint32_t grantTimeout); + bool grantChSlot(uint32_t dstId, uint32_t srcId, uint8_t slot, uint32_t grantTimeout); /// Helper to release the channel grant for the destination ID. virtual bool releaseGrant(uint32_t dstId, bool releaseAll); /// Helper to determine if the channel number is busy. diff --git a/src/dmr/packet/ControlSignaling.cpp b/src/dmr/packet/ControlSignaling.cpp index 1baf9da0..79c32de3 100644 --- a/src/dmr/packet/ControlSignaling.cpp +++ b/src/dmr/packet/ControlSignaling.cpp @@ -821,7 +821,7 @@ bool ControlSignaling::writeRF_CSBK_Grant(uint32_t srcId, uint32_t dstId, uint8_ } } else { - if (m_tscc->m_affiliations->grantCh(dstId, GRANT_TIMER_TIMEOUT)) { + if (m_tscc->m_affiliations->grantCh(dstId, srcId, GRANT_TIMER_TIMEOUT)) { chNo = m_tscc->m_affiliations->getGrantedCh(dstId); slot = m_tscc->m_affiliations->getGrantedSlot(dstId); //m_tscc->m_siteData.setChCnt(m_tscc->m_affiliations->getRFChCnt() + m_tscc->m_affiliations->getGrantedRFChCnt()); @@ -1056,7 +1056,7 @@ bool ControlSignaling::writeRF_CSBK_Data_Grant(uint32_t srcId, uint32_t dstId, u } } else { - if (m_tscc->m_affiliations->grantCh(dstId, GRANT_TIMER_TIMEOUT)) { + if (m_tscc->m_affiliations->grantCh(dstId, srcId, GRANT_TIMER_TIMEOUT)) { chNo = m_tscc->m_affiliations->getGrantedCh(dstId); slot = m_tscc->m_affiliations->getGrantedSlot(dstId); @@ -1219,6 +1219,29 @@ void ControlSignaling::writeRF_CSBK_U_Reg_Rsp(uint32_t srcId, uint8_t serviceOpt writeRF_CSBK(csbk.get()); } + +/// +/// Helper to write a grant packet. +/// +/// +/// +void ControlSignaling::writeRF_CSBK_Grant_LateEntry(uint32_t dstId, uint32_t srcId) +{ + Slot *m_tscc = m_slot->m_dmr->getTSCCSlot(); + + uint32_t chNo = m_tscc->m_affiliations->getGrantedCh(dstId); + uint8_t slot = m_tscc->m_affiliations->getGrantedSlot(dstId); + + std::unique_ptr csbk = new_unique(CSBK_TV_GRANT); + csbk->setLogicalCh1(chNo); + csbk->setSlotNo(slot - 1U); + + csbk->setSrcId(srcId); + csbk->setDstId(dstId); + + writeRF_CSBK(csbk.get()); +} + /// /// 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 88c99010..a75a18c2 100644 --- a/src/dmr/packet/ControlSignaling.h +++ b/src/dmr/packet/ControlSignaling.h @@ -101,6 +101,9 @@ namespace dmr /// Helper to write a unit registration response packet. void writeRF_CSBK_U_Reg_Rsp(uint32_t srcId, uint8_t serviceOptions); + /// 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); + /// Helper to write a TSCC Aloha broadcast packet on the RF interface. void writeRF_TSCC_Aloha(); /// Helper to write a TSCC Ann-Wd broadcast packet on the RF interface. diff --git a/src/lookups/AffiliationLookup.cpp b/src/lookups/AffiliationLookup.cpp index 70a30e5d..57429ed9 100644 --- a/src/lookups/AffiliationLookup.cpp +++ b/src/lookups/AffiliationLookup.cpp @@ -49,6 +49,7 @@ AffiliationLookup::AffiliationLookup(const char* name, bool verbose) : m_unitRegTable(), m_grpAffTable(), m_grantChTable(), + m_grantSrcIdTable(), m_grantTimers(), m_name(name), m_verbose(verbose) @@ -59,6 +60,7 @@ AffiliationLookup::AffiliationLookup(const char* name, bool verbose) : m_grpAffTable.clear(); m_grantChTable.clear(); + m_grantSrcIdTable.clear(); m_grantTimers.clear(); } @@ -238,9 +240,10 @@ std::vector AffiliationLookup::clearGroupAff(uint32_t dstId, bool rele /// Helper to grant a channel. /// /// +/// /// /// -bool AffiliationLookup::grantCh(uint32_t dstId, uint32_t grantTimeout) +bool AffiliationLookup::grantCh(uint32_t dstId, uint32_t srcId, uint32_t grantTimeout) { if (dstId == 0U) { return false; @@ -255,14 +258,15 @@ bool AffiliationLookup::grantCh(uint32_t dstId, uint32_t grantTimeout) m_rfChTable.erase(it); m_grantChTable[dstId] = chNo; + m_grantSrcIdTable[dstId] = srcId; m_rfGrantChCnt++; m_grantTimers[dstId] = Timer(1000U, grantTimeout); m_grantTimers[dstId].start(); if (m_verbose) { - LogMessage(LOG_HOST, "%s, granting channel, chNo = %u, dstId = %u", - m_name, chNo, dstId); + LogMessage(LOG_HOST, "%s, granting channel, chNo = %u, dstId = %u, srcId = %u", + m_name, chNo, dstId, srcId); } return true; @@ -321,7 +325,8 @@ bool AffiliationLookup::releaseGrant(uint32_t dstId, bool releaseAll) m_name, chNo, dstId); } - m_grantChTable[dstId] = 0U; + m_grantChTable.erase(dstId); + m_grantSrcIdTable.erase(dstId); m_rfChTable.push_back(chNo); if (m_rfGrantChCnt > 0U) { @@ -402,6 +407,24 @@ uint32_t AffiliationLookup::getGrantedCh(uint32_t dstId) return 0U; } +/// +/// Helper to get the source ID granted for the given destination ID. +/// +/// +/// +uint32_t AffiliationLookup::getGrantedSrcId(uint32_t dstId) +{ + if (dstId == 0U) { + return 0U; + } + + if (isGranted(dstId)) { + return m_grantSrcIdTable[dstId]; + } + + return 0U; +} + /// /// Helper to get RF channel data. /// diff --git a/src/lookups/AffiliationLookup.h b/src/lookups/AffiliationLookup.h index c8161ddb..fb753553 100644 --- a/src/lookups/AffiliationLookup.h +++ b/src/lookups/AffiliationLookup.h @@ -137,7 +137,7 @@ namespace lookups /// Gets the grant table. std::unordered_map grantTable() const { return m_grantChTable; } /// Helper to grant a channel. - virtual bool grantCh(uint32_t dstId, uint32_t grantTimeout); + virtual bool grantCh(uint32_t dstId, uint32_t srcId, uint32_t grantTimeout); /// Helper to start the destination ID grant timer. virtual void touchGrant(uint32_t dstId); /// Helper to release the channel grant for the destination ID. @@ -148,6 +148,8 @@ namespace lookups virtual bool isGranted(uint32_t dstId) const; /// Helper to get the channel granted for the given destination ID. virtual uint32_t getGrantedCh(uint32_t dstId); + /// Helper to get the source ID granted for the given destination ID. + virtual uint32_t getGrantedSrcId(uint32_t srcId); /// Helper to set RF channel data. void setRFChData(const std::unordered_map chData) { m_rfChDataTable = chData; } @@ -177,6 +179,7 @@ namespace lookups std::unordered_map m_grpAffTable; std::unordered_map m_grantChTable; + std::unordered_map m_grantSrcIdTable; std::unordered_map m_grantTimers; const char *m_name; diff --git a/src/nxdn/packet/Trunk.cpp b/src/nxdn/packet/Trunk.cpp index 37461b2f..46573347 100644 --- a/src/nxdn/packet/Trunk.cpp +++ b/src/nxdn/packet/Trunk.cpp @@ -488,7 +488,7 @@ bool Trunk::writeRF_Message_Grant(uint32_t srcId, uint32_t dstId, uint8_t servic } } else { - if (m_nxdn->m_affiliations.grantCh(dstId, GRANT_TIMER_TIMEOUT)) { + if (m_nxdn->m_affiliations.grantCh(dstId, srcId, GRANT_TIMER_TIMEOUT)) { chNo = m_nxdn->m_affiliations.getGrantedCh(dstId); } } diff --git a/src/p25/packet/Trunk.cpp b/src/p25/packet/Trunk.cpp index d80904fd..7cbabf10 100644 --- a/src/p25/packet/Trunk.cpp +++ b/src/p25/packet/Trunk.cpp @@ -2216,7 +2216,7 @@ bool Trunk::writeRF_TSDU_Grant(uint32_t srcId, uint32_t dstId, uint8_t serviceOp } } else { - if (m_p25->m_affiliations.grantCh(dstId, GRANT_TIMER_TIMEOUT)) { + if (m_p25->m_affiliations.grantCh(dstId, srcId, GRANT_TIMER_TIMEOUT)) { chNo = m_p25->m_affiliations.getGrantedCh(dstId); m_p25->m_siteData.setChCnt(m_p25->m_affiliations.getRFChCnt() + m_p25->m_affiliations.getGrantedRFChCnt()); } @@ -2360,7 +2360,7 @@ bool Trunk::writeRF_TSDU_SNDCP_Grant(uint32_t srcId, uint32_t dstId, bool skip, return false; } else { - if (m_p25->m_affiliations.grantCh(srcId, GRANT_TIMER_TIMEOUT)) { + if (m_p25->m_affiliations.grantCh(srcId, srcId, GRANT_TIMER_TIMEOUT)) { uint32_t chNo = m_p25->m_affiliations.getGrantedCh(srcId); osp->setGrpVchNo(chNo); osp->setDataChnNo(chNo);