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);