diff --git a/src/common/lookups/AffiliationLookup.cpp b/src/common/lookups/AffiliationLookup.cpp index 35bb546d..a441c4ad 100644 --- a/src/common/lookups/AffiliationLookup.cpp +++ b/src/common/lookups/AffiliationLookup.cpp @@ -38,6 +38,7 @@ AffiliationLookup::AffiliationLookup(const std::string name, ChannelLookup* chan m_uuGrantedTable(), m_netGrantedTable(), m_grantTimers(), + m_grantCallTimers(), m_releaseGrant(nullptr), m_unitDereg(nullptr), m_name(), @@ -364,6 +365,8 @@ bool AffiliationLookup::grantCh(uint32_t dstId, uint32_t srcId, uint32_t grantTi m_grantTimers[dstId] = Timer(1000U, grantTimeout); m_grantTimers[dstId].start(); + m_grantCallTimers[dstId] = StopWatch(); + m_grantCallTimers[dstId].start(); if (m_verbose) { LogInfoEx(LOG_HOST, "%s, granting channel, chNo = %u, dstId = %u, srcId = %u, group = %u", @@ -453,6 +456,8 @@ bool AffiliationLookup::releaseGrant(uint32_t dstId, bool releaseAll) m_uuGrantedTable.erase(dstId); m_netGrantedTable.erase(dstId); + m_grantCallTimers.erase(dstId); + if (m_chLookup != nullptr) { m_chLookup->freeRFCh(chNo); } @@ -671,6 +676,32 @@ uint32_t AffiliationLookup::getGrantedSrcId(uint32_t dstId) return 0U; } +/* Helper to get the current elapsed time for the given destination ID. */ + +uint32_t AffiliationLookup::getGrantCallElapsed(uint32_t dstId) +{ + if (dstId == 0U) { + return 0U; + } + + __spinlock(); + + if (isGranted(dstId)) { + // lookup dynamic channel grant timer table entry + m_grantCallTimers.lock(false); + auto it = m_grantCallTimers.find(dstId); + if (it != m_grantCallTimers.end()) { + uint32_t time = it->second.elapsed(); + + m_grantCallTimers.unlock(); + return time; + } + m_grantCallTimers.unlock(); + } + + return 0U; +} + /* Updates the processor by the passed number of milliseconds. */ void AffiliationLookup::clock(uint32_t ms) diff --git a/src/common/lookups/AffiliationLookup.h b/src/common/lookups/AffiliationLookup.h index 5366a801..c364414f 100644 --- a/src/common/lookups/AffiliationLookup.h +++ b/src/common/lookups/AffiliationLookup.h @@ -25,6 +25,7 @@ #include "common/concurrent/vector.h" #include "common/concurrent/unordered_map.h" #include "common/lookups/ChannelLookup.h" +#include "common/StopWatch.h" #include "common/Timer.h" #include @@ -234,6 +235,13 @@ namespace lookups * @returns uint32_t Source Radio ID. */ virtual uint32_t getGrantedSrcId(uint32_t dstId); + /** + * @brief Helper to get the current elapsed time for the given destination ID. + * @note This is the time since the grant was first granted. + * @param dstId Destination Address. + * @returns uint32_t Current elapsed time for the channel grant. + */ + uint32_t getGrantCallElapsed(uint32_t dstId); /** * @brief Gets the count of granted RF channels. * @returns uint8_t Total number of granted RF channels. @@ -303,6 +311,7 @@ namespace lookups concurrent::unordered_map m_uuGrantedTable; concurrent::unordered_map m_netGrantedTable; concurrent::unordered_map m_grantTimers; + concurrent::unordered_map m_grantCallTimers; // chNo srcId dstId slot std::function m_releaseGrant; diff --git a/src/host/Host.cpp b/src/host/Host.cpp index f262b47e..8175091f 100644 --- a/src/host/Host.cpp +++ b/src/host/Host.cpp @@ -1371,7 +1371,7 @@ json::object Host::getStatus() uint32_t peerId = m_voiceChPeerId[chNo]; chData["peerId"].set(peerId); - uint32_t dstId = 0U, srcId = 0U; + uint32_t dstId = 0U, srcId = 0U, grantElapsedTime = 0U; // fetch affiliations from DMR if we're a DMR CC if (m_dmrTSCCData && m_dmr->affiliations() != nullptr) { @@ -1382,8 +1382,10 @@ json::object Host::getStatus() } dstId = m_dmr->affiliations()->getGrantedDstByCh(chNo); - if (dstId > 0U) + if (dstId > 0U) { srcId = m_dmr->affiliations()->getGrantedSrcId(dstId); + grantElapsedTime = m_dmr->affiliations()->getGrantCallElapsed(dstId); + } } // fetch affiliations from P25 if we're a P25 CC @@ -1395,8 +1397,10 @@ json::object Host::getStatus() } dstId = m_p25->affiliations()->getGrantedDstByCh(chNo); - if (dstId > 0U) + if (dstId > 0U) { srcId = m_p25->affiliations()->getGrantedSrcId(dstId); + grantElapsedTime = m_p25->affiliations()->getGrantCallElapsed(dstId); + } } // fetch affiliations from NXDN if we're a NXDN CC @@ -1408,12 +1412,15 @@ json::object Host::getStatus() } dstId = m_nxdn->affiliations()->getGrantedDstByCh(chNo); - if (dstId > 0U) + if (dstId > 0U) { srcId = m_nxdn->affiliations()->getGrantedSrcId(dstId); + grantElapsedTime = m_nxdn->affiliations()->getGrantCallElapsed(dstId); + } } chData["lastDstId"].set(dstId); chData["lastSrcId"].set(srcId); + chData["grantElapsedTime"].set(grantElapsedTime); vcChannels.push_back(json::value(chData)); }