From 685ea4df14c02e64a54c128bd4b72898f888a8b9 Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Sat, 9 Dec 2023 17:18:37 -0500 Subject: [PATCH] implement partial fix for trunked UU calls (calls can be made now, but operation is still glitchy); --- configs/config.example.yml | 2 +- src/RingBuffer.h | 4 +- src/dmr/lookups/DMRAffiliationLookup.cpp | 13 ++-- src/dmr/lookups/DMRAffiliationLookup.h | 4 +- src/dmr/packet/ControlSignaling.cpp | 4 +- src/lookups/AffiliationLookup.cpp | 30 ++++++- src/lookups/AffiliationLookup.h | 5 +- src/nxdn/packet/ControlSignaling.cpp | 2 +- src/p25/lc/tsbk/OSP_UU_VCH_GRANT_UPD.cpp | 99 ++++++++++++++++++++++++ src/p25/lc/tsbk/OSP_UU_VCH_GRANT_UPD.h | 60 ++++++++++++++ src/p25/lc/tsbk/TSBKFactory.h | 1 + src/p25/packet/ControlSignaling.cpp | 52 ++++++++----- 12 files changed, 240 insertions(+), 36 deletions(-) create mode 100644 src/p25/lc/tsbk/OSP_UU_VCH_GRANT_UPD.cpp create mode 100644 src/p25/lc/tsbk/OSP_UU_VCH_GRANT_UPD.h diff --git a/configs/config.example.yml b/configs/config.example.yml index 82293b49..0a760902 100644 --- a/configs/config.example.yml +++ b/configs/config.example.yml @@ -215,7 +215,7 @@ protocols: # Flag indicating whether or not the host will acknowledge message packets. noMessageAck: true # Flag indicating that unit-to-unit availiability checks should be performed for a private call. - unitToUnitAvailCheck: true + unitToUnitAvailCheck: false # Flag indicating explicit source ID support is enabled. allowExplicitSourceId: true # Flag indicating whether or not the host will respond to SNDCP data grant requests. diff --git a/src/RingBuffer.h b/src/RingBuffer.h index ebd01d96..36022aa0 100644 --- a/src/RingBuffer.h +++ b/src/RingBuffer.h @@ -75,8 +75,8 @@ public: /// True, if data is added to ring buffer, otherwise false. bool addData(const T* buffer, uint32_t length) { - if (length >= freeSpace()) { - LogError(LOG_HOST, "**** Overflow in %s ring buffer, %u >= %u, clearing the buffer", m_name, length, freeSpace()); + if (length > freeSpace()) { + LogError(LOG_HOST, "**** Overflow in %s ring buffer, %u > %u, clearing the buffer", m_name, length, freeSpace()); clear(); return false; } diff --git a/src/dmr/lookups/DMRAffiliationLookup.cpp b/src/dmr/lookups/DMRAffiliationLookup.cpp index 84a36c3e..f0d4015d 100644 --- a/src/dmr/lookups/DMRAffiliationLookup.cpp +++ b/src/dmr/lookups/DMRAffiliationLookup.cpp @@ -63,9 +63,10 @@ DMRAffiliationLookup::~DMRAffiliationLookup() /// /// /// +/// /// /// -bool DMRAffiliationLookup::grantCh(uint32_t dstId, uint32_t srcId, uint32_t grantTimeout, bool netGranted) +bool DMRAffiliationLookup::grantCh(uint32_t dstId, uint32_t srcId, uint32_t grantTimeout, bool grp, bool netGranted) { uint32_t chNo = m_rfChTable.at(0); uint8_t slot = getAvailableSlotForChannel(chNo); @@ -74,7 +75,7 @@ bool DMRAffiliationLookup::grantCh(uint32_t dstId, uint32_t srcId, uint32_t gran return false; } - return grantChSlot(dstId, srcId, slot, grantTimeout, netGranted); + return grantChSlot(dstId, srcId, slot, grantTimeout, grp, netGranted); } /// @@ -84,9 +85,10 @@ bool DMRAffiliationLookup::grantCh(uint32_t dstId, uint32_t srcId, uint32_t gran /// /// /// +/// /// /// -bool DMRAffiliationLookup::grantChSlot(uint32_t dstId, uint32_t srcId, uint8_t slot, uint32_t grantTimeout, bool netGranted) +bool DMRAffiliationLookup::grantChSlot(uint32_t dstId, uint32_t srcId, uint8_t slot, uint32_t grantTimeout, bool grp, bool netGranted) { if (dstId == 0U) { return false; @@ -111,14 +113,15 @@ bool DMRAffiliationLookup::grantChSlot(uint32_t dstId, uint32_t srcId, uint8_t s m_grantChSlotTable[dstId] = std::make_tuple(chNo, slot); m_rfGrantChCnt++; + m_uuGrantedTable[dstId] = !grp; m_netGrantedTable[dstId] = netGranted; m_grantTimers[dstId] = Timer(1000U, grantTimeout); m_grantTimers[dstId].start(); if (m_verbose) { - LogMessage(LOG_HOST, "%s, granting channel, chNo = %u, slot = %u, dstId = %u", - m_name, chNo, slot, dstId); + LogMessage(LOG_HOST, "%s, granting channel, chNo = %u, slot = %u, dstId = %u, group = %u", + m_name, chNo, slot, dstId, grp); } return true; diff --git a/src/dmr/lookups/DMRAffiliationLookup.h b/src/dmr/lookups/DMRAffiliationLookup.h index 0809681d..b20086f3 100644 --- a/src/dmr/lookups/DMRAffiliationLookup.h +++ b/src/dmr/lookups/DMRAffiliationLookup.h @@ -49,9 +49,9 @@ namespace dmr virtual ~DMRAffiliationLookup(); /// Helper to grant a channel. - bool grantCh(uint32_t dstId, uint32_t srcId, uint32_t grantTimeout, bool netGranted) override; + bool grantCh(uint32_t dstId, uint32_t srcId, uint32_t grantTimeout, bool grp, bool netGranted) override; /// Helper to grant a channel and slot. - bool grantChSlot(uint32_t dstId, uint32_t srcId, uint8_t slot, uint32_t grantTimeout, bool netGranted); + bool grantChSlot(uint32_t dstId, uint32_t srcId, uint8_t slot, uint32_t grantTimeout, bool grp, bool netGranted); /// Helper to release the channel grant for the destination ID. bool releaseGrant(uint32_t dstId, bool releaseAll) override; /// Helper to determine if the channel number is busy. diff --git a/src/dmr/packet/ControlSignaling.cpp b/src/dmr/packet/ControlSignaling.cpp index 5a0a28bc..f062e557 100644 --- a/src/dmr/packet/ControlSignaling.cpp +++ b/src/dmr/packet/ControlSignaling.cpp @@ -860,7 +860,7 @@ bool ControlSignaling::writeRF_CSBK_Grant(uint32_t srcId, uint32_t dstId, uint8_ } } else { - if (m_tscc->m_affiliations->grantCh(dstId, srcId, GRANT_TIMER_TIMEOUT, net)) { + if (m_tscc->m_affiliations->grantCh(dstId, srcId, GRANT_TIMER_TIMEOUT, grp, net)) { 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()); @@ -1149,7 +1149,7 @@ bool ControlSignaling::writeRF_CSBK_Data_Grant(uint32_t srcId, uint32_t dstId, u } } else { - if (m_tscc->m_affiliations->grantCh(dstId, srcId, GRANT_TIMER_TIMEOUT, net)) { + if (m_tscc->m_affiliations->grantCh(dstId, srcId, GRANT_TIMER_TIMEOUT, grp, net)) { chNo = m_tscc->m_affiliations->getGrantedCh(dstId); slot = m_tscc->m_affiliations->getGrantedSlot(dstId); diff --git a/src/lookups/AffiliationLookup.cpp b/src/lookups/AffiliationLookup.cpp index b73f86fb..89592e48 100644 --- a/src/lookups/AffiliationLookup.cpp +++ b/src/lookups/AffiliationLookup.cpp @@ -50,6 +50,7 @@ AffiliationLookup::AffiliationLookup(const char* name, bool verbose) : m_grpAffTable(), m_grantChTable(), m_grantSrcIdTable(), + m_uuGrantedTable(), m_netGrantedTable(), m_grantTimers(), m_releaseGrant(nullptr), @@ -246,9 +247,10 @@ std::vector AffiliationLookup::clearGroupAff(uint32_t dstId, bool rele /// /// /// +/// /// /// -bool AffiliationLookup::grantCh(uint32_t dstId, uint32_t srcId, uint32_t grantTimeout, bool netGranted) +bool AffiliationLookup::grantCh(uint32_t dstId, uint32_t srcId, uint32_t grantTimeout, bool grp, bool netGranted) { if (dstId == 0U) { return false; @@ -266,14 +268,15 @@ bool AffiliationLookup::grantCh(uint32_t dstId, uint32_t srcId, uint32_t grantTi m_grantSrcIdTable[dstId] = srcId; m_rfGrantChCnt++; + m_uuGrantedTable[dstId] = !grp; m_netGrantedTable[dstId] = netGranted; m_grantTimers[dstId] = Timer(1000U, grantTimeout); m_grantTimers[dstId].start(); if (m_verbose) { - LogMessage(LOG_HOST, "%s, granting channel, chNo = %u, dstId = %u, srcId = %u", - m_name, chNo, dstId, srcId); + LogMessage(LOG_HOST, "%s, granting channel, chNo = %u, dstId = %u, srcId = %u, group = %u", + m_name, chNo, dstId, srcId, grp); } return true; @@ -338,6 +341,7 @@ bool AffiliationLookup::releaseGrant(uint32_t dstId, bool releaseAll) m_grantChTable.erase(dstId); m_grantSrcIdTable.erase(dstId); + m_uuGrantedTable.erase(dstId); m_netGrantedTable.erase(dstId); m_rfChTable.push_back(chNo); @@ -401,6 +405,26 @@ bool AffiliationLookup::isGranted(uint32_t dstId) const } } +/// +/// Helper to determine if the destination ID is network granted. +/// +/// +/// +bool AffiliationLookup::isGroup(uint32_t dstId) const +{ + if (dstId == 0U) { + return true; + } + + // lookup dynamic channel grant table entry + try { + bool uu = m_uuGrantedTable.at(dstId); + return !uu; + } catch (...) { + return true; + } +} + /// /// Helper to determine if the destination ID is network granted. /// diff --git a/src/lookups/AffiliationLookup.h b/src/lookups/AffiliationLookup.h index 61f7b858..7a507f57 100644 --- a/src/lookups/AffiliationLookup.h +++ b/src/lookups/AffiliationLookup.h @@ -146,7 +146,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 srcId, uint32_t grantTimeout, bool netGranted); + virtual bool grantCh(uint32_t dstId, uint32_t srcId, uint32_t grantTimeout, bool grp, bool netGranted); /// Helper to start the destination ID grant timer. virtual void touchGrant(uint32_t dstId); /// Helper to release the channel grant for the destination ID. @@ -155,6 +155,8 @@ namespace lookups virtual bool isChBusy(uint32_t chNo) const; /// Helper to determine if the destination ID is already granted. virtual bool isGranted(uint32_t dstId) const; + /// Helper to determine if the destination ID granted is a group or not. + virtual bool isGroup(uint32_t dstId) const; /// Helper to determine if the destination ID is granted by network traffic. virtual bool isNetGranted(uint32_t dstId) const; /// Helper to get the channel granted for the given destination ID. @@ -194,6 +196,7 @@ namespace lookups std::unordered_map m_grantChTable; std::unordered_map m_grantSrcIdTable; + std::unordered_map m_uuGrantedTable; std::unordered_map m_netGrantedTable; std::unordered_map m_grantTimers; diff --git a/src/nxdn/packet/ControlSignaling.cpp b/src/nxdn/packet/ControlSignaling.cpp index f986df19..dc24e282 100644 --- a/src/nxdn/packet/ControlSignaling.cpp +++ b/src/nxdn/packet/ControlSignaling.cpp @@ -563,7 +563,7 @@ bool ControlSignaling::writeRF_Message_Grant(uint32_t srcId, uint32_t dstId, uin } } else { - if (m_nxdn->m_affiliations.grantCh(dstId, srcId, GRANT_TIMER_TIMEOUT, net)) { + if (m_nxdn->m_affiliations.grantCh(dstId, srcId, GRANT_TIMER_TIMEOUT, grp, net)) { chNo = m_nxdn->m_affiliations.getGrantedCh(dstId); } } diff --git a/src/p25/lc/tsbk/OSP_UU_VCH_GRANT_UPD.cpp b/src/p25/lc/tsbk/OSP_UU_VCH_GRANT_UPD.cpp new file mode 100644 index 00000000..04a287a5 --- /dev/null +++ b/src/p25/lc/tsbk/OSP_UU_VCH_GRANT_UPD.cpp @@ -0,0 +1,99 @@ +/** +* Digital Voice Modem - Host Software +* GPLv2 Open Source. Use is subject to license terms. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* @package DVM / Host Software +* +*/ +/* +* Copyright (C) 2023 by Bryan Biedenkapp N2PLL +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#include "Defines.h" +#include "p25/lc/tsbk/OSP_UU_VCH_GRANT_UPD.h" +#include "Log.h" +#include "Utils.h" + +using namespace p25::lc::tsbk; +using namespace p25::lc; +using namespace p25; + +#include +#include + +// --------------------------------------------------------------------------- +// Public Class Members +// --------------------------------------------------------------------------- + +/// +/// Initializes a new instance of the OSP_UU_VCH_GRANT_UPD class. +/// +OSP_UU_VCH_GRANT_UPD::OSP_UU_VCH_GRANT_UPD() : TSBK() +{ + m_lco = TSBK_OSP_UU_VCH_GRANT_UPD; +} + +/// +/// Decode a trunking signalling block. +/// +/// +/// +/// True, if TSBK was decoded, otherwise false. +bool OSP_UU_VCH_GRANT_UPD::decode(const uint8_t* data, bool rawTSBK) +{ + assert(data != NULL); + + /* stub */ + + return true; +} + +/// +/// Encode a trunking signalling block. +/// +/// +/// +/// +void OSP_UU_VCH_GRANT_UPD::encode(uint8_t* data, bool rawTSBK, bool noTrellis) +{ + assert(data != NULL); + + ulong64_t tsbkValue = 0U; + + if (m_grpVchId != 0U) { + tsbkValue = m_grpVchId; // Channel ID + } + else { + tsbkValue = m_siteData.channelId(); // Channel ID + } + tsbkValue = (tsbkValue << 12) + m_grpVchNo; // Channel Number + tsbkValue = (tsbkValue << 24) + m_dstId; // Target Address + tsbkValue = (tsbkValue << 24) + m_srcId; // Source Address + + std::unique_ptr tsbk = TSBK::fromValue(tsbkValue); + TSBK::encode(data, tsbk.get(), rawTSBK, noTrellis); +} + +/// +/// Returns a string that represents the current TSBK. +/// +/// +/// +std::string OSP_UU_VCH_GRANT_UPD::toString(bool isp) +{ + return std::string("TSBK_OSP_UU_VCH_GRANT_UPD (Unit-to-Unit Voice Channel Grant Update)"); +} diff --git a/src/p25/lc/tsbk/OSP_UU_VCH_GRANT_UPD.h b/src/p25/lc/tsbk/OSP_UU_VCH_GRANT_UPD.h new file mode 100644 index 00000000..a618902f --- /dev/null +++ b/src/p25/lc/tsbk/OSP_UU_VCH_GRANT_UPD.h @@ -0,0 +1,60 @@ +/** +* Digital Voice Modem - Host Software +* GPLv2 Open Source. Use is subject to license terms. +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* @package DVM / Host Software +* +*/ +/* +* Copyright (C) 2023 by Bryan Biedenkapp N2PLL +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ +#if !defined(__P25_LC_TSBK__OSP_UU_VCH_GRANT_UPD_H__) +#define __P25_LC_TSBK__OSP_UU_VCH_GRANT_UPD_H__ + +#include "Defines.h" +#include "p25/lc/TSBK.h" + +namespace p25 +{ + namespace lc + { + namespace tsbk + { + // --------------------------------------------------------------------------- + // Class Declaration + // Implements UU VCH GRANT UPD - Unit-to-Unit Voice Channel Grant Update. + // --------------------------------------------------------------------------- + + class HOST_SW_API OSP_UU_VCH_GRANT_UPD : public TSBK { + public: + /// Initializes a new instance of the OSP_UU_VCH_GRANT_UPD class. + OSP_UU_VCH_GRANT_UPD(); + + /// Decode a trunking signalling block. + bool decode(const uint8_t* data, bool rawTSBK = false); + /// Encode a trunking signalling block. + void encode(uint8_t* data, bool rawTSBK = false, bool noTrellis = false); + + /// Returns a string that represents the current TSBK. + virtual std::string toString(bool isp = false) override; + }; + } // namespace tsbk + } // namespace lc +} // namespace p25 + +#endif // __P25_LC_TSBK__OSP_UU_VCH_GRANT_UPD_H__ diff --git a/src/p25/lc/tsbk/TSBKFactory.h b/src/p25/lc/tsbk/TSBKFactory.h index 58412c10..0e09c9bd 100644 --- a/src/p25/lc/tsbk/TSBKFactory.h +++ b/src/p25/lc/tsbk/TSBKFactory.h @@ -80,6 +80,7 @@ #include "p25/lc/tsbk/OSP_TSBK_RAW.h" #include "p25/lc/tsbk/OSP_U_DEREG_ACK.h" #include "p25/lc/tsbk/OSP_U_REG_CMD.h" +#include "p25/lc/tsbk/OSP_UU_VCH_GRANT_UPD.h" #include "p25/lc/AMBT.h" #include "p25/lc/tsbk/MBT_IOSP_ACK_RSP.h" diff --git a/src/p25/packet/ControlSignaling.cpp b/src/p25/packet/ControlSignaling.cpp index 390e2300..3eb017a5 100644 --- a/src/p25/packet/ControlSignaling.cpp +++ b/src/p25/packet/ControlSignaling.cpp @@ -310,10 +310,6 @@ bool ControlSignaling::process(uint8_t* data, uint32_t len, std::unique_ptrgetResponse() == P25_ANS_RSP_PROCEED) { - if (m_p25->m_ackTSBKRequests) { - writeRF_TSDU_ACK_FNE(dstId, TSBK_IOSP_UU_VCH, false, true); - } - if (m_p25->m_authoritative) { uint8_t serviceOptions = (tsbk->getEmergency() ? 0x80U : 0x00U) + // Emergency Flag (tsbk->getEncrypted() ? 0x40U : 0x00U) + // Encrypted Flag @@ -325,12 +321,10 @@ bool ControlSignaling::process(uint8_t* data, uint32_t len, std::unique_ptrgetResponse() == P25_ANS_RSP_DENY) { - writeRF_TSDU_ACK_FNE(dstId, TSBK_IOSP_UU_VCH, false, true); - writeRF_TSDU_Deny(P25_WUID_FNE, dstId, P25_DENY_RSN_TGT_UNIT_REFUSED, TSBK_IOSP_UU_VCH); + writeRF_TSDU_Deny(P25_WUID_FNE, dstId, P25_DENY_RSN_TGT_UNIT_REFUSED, TSBK_IOSP_UU_ANS); } else if (iosp->getResponse() == P25_ANS_RSP_WAIT) { - writeRF_TSDU_ACK_FNE(dstId, TSBK_IOSP_UU_VCH, false, true); - writeRF_TSDU_Queue(P25_WUID_FNE, dstId, P25_QUE_RSN_TGT_UNIT_QUEUED, TSBK_IOSP_UU_VCH, false, false); + writeRF_TSDU_Queue(P25_WUID_FNE, dstId, P25_QUE_RSN_TGT_UNIT_QUEUED, TSBK_IOSP_UU_ANS, false, false); } } break; @@ -2262,7 +2256,7 @@ bool ControlSignaling::writeRF_TSDU_Grant(uint32_t srcId, uint32_t dstId, uint8_ } } else { - if (m_p25->m_affiliations.grantCh(dstId, srcId, GRANT_TIMER_TIMEOUT, net)) { + if (m_p25->m_affiliations.grantCh(dstId, srcId, GRANT_TIMER_TIMEOUT, grp, net)) { chNo = m_p25->m_affiliations.getGrantedCh(dstId); m_p25->m_siteData.setChCnt(m_p25->m_affiliations.getRFChCnt() + m_p25->m_affiliations.getGrantedRFChCnt()); } @@ -2429,8 +2423,7 @@ void ControlSignaling::writeRF_TSDU_Grant_Update() if (m_mbfGrpGrntCnt >= m_p25->m_affiliations.grantSize()) m_mbfGrpGrntCnt = 0U; - std::unique_ptr osp = new_unique(OSP_GRP_VCH_GRANT_UPD); - DEBUG_LOG_TSBK(osp->toString()); + std::unique_ptr osp; bool noData = false; uint8_t i = 0U; @@ -2444,6 +2437,7 @@ void ControlSignaling::writeRF_TSDU_Grant_Update() else { uint32_t dstId = entry.first; uint32_t chNo = entry.second; + bool grp = m_p25->m_affiliations.isGroup(dstId); ::lookups::VoiceChData voiceChData = m_p25->m_affiliations.getRFChData(chNo); @@ -2453,14 +2447,34 @@ void ControlSignaling::writeRF_TSDU_Grant_Update() break; } else { - // transmit group voice grant update - osp->setLCO(TSBK_OSP_GRP_VCH_GRANT_UPD); - osp->setDstId(dstId); - osp->setGrpVchId(voiceChData.chId()); - osp->setGrpVchNo(chNo); + if (grp) { + osp = new_unique(OSP_GRP_VCH_GRANT_UPD); + DEBUG_LOG_TSBK(osp->toString()); - m_mbfGrpGrntCnt++; - break; + // transmit group voice grant update + osp->setLCO(TSBK_OSP_GRP_VCH_GRANT_UPD); + osp->setDstId(dstId); + osp->setGrpVchId(voiceChData.chId()); + osp->setGrpVchNo(chNo); + + m_mbfGrpGrntCnt++; + break; + } else { + uint32_t srcId = m_p25->m_affiliations.getGrantedSrcId(dstId); + + osp = new_unique(OSP_UU_VCH_GRANT_UPD); + DEBUG_LOG_TSBK(osp->toString()); + + // transmit group voice grant update + osp->setLCO(TSBK_OSP_UU_VCH_GRANT_UPD); + osp->setSrcId(srcId); + osp->setDstId(dstId); + osp->setGrpVchId(voiceChData.chId()); + osp->setGrpVchNo(chNo); + + m_mbfGrpGrntCnt++; + break; + } } } } @@ -2522,7 +2536,7 @@ bool ControlSignaling::writeRF_TSDU_SNDCP_Grant(uint32_t srcId, uint32_t dstId, return false; } else { - if (m_p25->m_affiliations.grantCh(srcId, srcId, GRANT_TIMER_TIMEOUT, net)) { + if (m_p25->m_affiliations.grantCh(srcId, srcId, GRANT_TIMER_TIMEOUT, false, net)) { uint32_t chNo = m_p25->m_affiliations.getGrantedCh(srcId); ::lookups::VoiceChData voiceChData = m_p25->m_affiliations.getRFChData(chNo);