From 4aaf9e5494a4edb291cdd33260b53e832272e55f Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Sat, 9 Dec 2023 23:35:53 -0500 Subject: [PATCH] readd an extremely undocumented feature, that no one ever should use, for a close friend who asked nicely; --- src/p25/Control.cpp | 21 ++++ src/p25/Control.h | 2 + src/p25/packet/ControlSignaling.cpp | 3 + src/p25/packet/Voice.cpp | 146 +++++++++++++++++++++++++++- 4 files changed, 168 insertions(+), 4 deletions(-) diff --git a/src/p25/Control.cpp b/src/p25/Control.cpp index b0981ee0..cc082531 100644 --- a/src/p25/Control.cpp +++ b/src/p25/Control.cpp @@ -102,6 +102,7 @@ Control::Control(bool authoritative, uint32_t nac, uint32_t callHang, uint32_t q m_duplex(duplex), m_enableControl(false), m_dedicatedControl(false), + m_voiceOnControl(false), m_ackTSBKRequests(true), m_disableNetworkGrant(false), m_disableNetworkHDU(false), @@ -303,6 +304,17 @@ void Control::setOptions(yaml::Node& conf, bool supervisor, const std::string cw m_dedicatedControl = false; } + m_voiceOnControl = control["voiceOnControl"].as(false); + + if (m_voiceOnControl) { + LogWarning(LOG_P25, "HERE BE DRAGONS! Voice on Control is an unsupported/undocumented configuration; are you sure you should be doing this?"); + } + + // if control channel is off for voice on control off + if (!m_enableControl) { + m_voiceOnControl = false; + } + m_controlOnly = p25Protocol["controlOnly"].as(false); // if we're a dedicated control channel don't set the control only flag @@ -326,6 +338,11 @@ void Control::setOptions(yaml::Node& conf, bool supervisor, const std::string cw yaml::Node controlCh = rfssConfig["controlCh"]; m_notifyCC = controlCh["notifyEnable"].as(false); + // voice on control forcibly disables CC notification + if (m_voiceOnControl) { + m_notifyCC = false; + } + /* ** Voice Silence and Frame Loss Thresholds */ @@ -633,6 +650,10 @@ bool Control::processFrame(uint8_t* data, uint32_t len) if (!m_dedicatedControl || m_control->m_convFallback) ret = m_voice->process(data, len); + else { + if (m_voiceOnControl && m_affiliations.isChBusy(m_siteData.channelNo())) + ret = m_voice->process(data, len); + } break; case P25_DUID_TDU: diff --git a/src/p25/Control.h b/src/p25/Control.h index 9800f120..59a1cf9a 100644 --- a/src/p25/Control.h +++ b/src/p25/Control.h @@ -171,12 +171,14 @@ namespace p25 bool m_duplex; bool m_enableControl; bool m_dedicatedControl; + bool m_voiceOnControl; bool m_controlOnly; bool m_ackTSBKRequests; bool m_disableNetworkGrant; bool m_disableNetworkHDU; bool m_allowExplicitSourceId; + ::lookups::IdenTableLookup* m_idenTable; ::lookups::RadioIdLookup* m_ridLookup; ::lookups::TalkgroupRulesLookup* m_tidLookup; diff --git a/src/p25/packet/ControlSignaling.cpp b/src/p25/packet/ControlSignaling.cpp index 3eb017a5..0274343d 100644 --- a/src/p25/packet/ControlSignaling.cpp +++ b/src/p25/packet/ControlSignaling.cpp @@ -2418,6 +2418,9 @@ bool ControlSignaling::writeRF_TSDU_Grant(uint32_t srcId, uint32_t dstId, uint8_ /// void ControlSignaling::writeRF_TSDU_Grant_Update() { + if (m_p25->m_voiceOnControl) + return; + // write group voice grant update if (m_p25->m_affiliations.grantSize() > 0) { if (m_mbfGrpGrntCnt >= m_p25->m_affiliations.grantSize()) diff --git a/src/p25/packet/Voice.cpp b/src/p25/packet/Voice.cpp index f8cdefd1..9c5fb8bb 100644 --- a/src/p25/packet/Voice.cpp +++ b/src/p25/packet/Voice.cpp @@ -34,6 +34,8 @@ #include "p25/packet/ControlSignaling.h" #include "p25/acl/AccessControl.h" #include "p25/dfsi/DFSIDefines.h" +#include "p25/lc/tsbk/OSP_GRP_VCH_GRANT_UPD.h" +#include "p25/lc/tsbk/OSP_UU_VCH_GRANT_UPD.h" #include "p25/lc/tdulc/TDULCFactory.h" #include "p25/P25Utils.h" #include "p25/Sync.h" @@ -422,8 +424,42 @@ bool Voice::process(uint8_t* data, uint32_t len) } // conventional registration or DVRS support? - if (m_p25->m_enableControl && !m_p25->m_dedicatedControl) { + if ((m_p25->m_enableControl && !m_p25->m_dedicatedControl) || m_p25->m_voiceOnControl) { m_p25->m_control->writeRF_TSDU_Grant(srcId, dstId, serviceOptions, group, true, true); + + // if voice on control; insert grant updates before voice traffic + if (m_p25->m_voiceOnControl) { + uint32_t chNo = m_p25->m_affiliations.getGrantedCh(dstId); + ::lookups::VoiceChData voiceChData = m_p25->m_affiliations.getRFChData(chNo); + bool grp = m_p25->m_affiliations.isGroup(dstId); + + std::unique_ptr osp; + + if (grp) { + osp = new_unique(lc::tsbk::OSP_GRP_VCH_GRANT_UPD); + + // transmit group voice grant update + osp->setLCO(TSBK_OSP_GRP_VCH_GRANT_UPD); + osp->setDstId(dstId); + osp->setGrpVchId(voiceChData.chId()); + osp->setGrpVchNo(chNo); + } + else { + uint32_t srcId = m_p25->m_affiliations.getGrantedSrcId(dstId); + + osp = new_unique(lc::tsbk::OSP_UU_VCH_GRANT_UPD); + + // 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); + } + + for (int i = 0; i < 3; i++) + m_p25->m_control->writeRF_TSDU_SBF(osp.get(), false, false, false, false); + } } m_hadVoice = true; @@ -489,6 +525,40 @@ bool Voice::process(uint8_t* data, uint32_t len) LogWarning(LOG_RF, P25_HDU_STR ", not transmitted; possible late entry, dstId = %u, algo = $%02X, kid = $%04X", m_rfLastHDU.getDstId(), m_rfLastHDU.getAlgId(), m_rfLastHDU.getKId()); } + // if voice on control; insert group voice channel updates directly after HDU but before LDUs + if (m_p25->m_voiceOnControl) { + uint32_t chNo = m_p25->m_affiliations.getGrantedCh(dstId); + ::lookups::VoiceChData voiceChData = m_p25->m_affiliations.getRFChData(chNo); + bool grp = m_p25->m_affiliations.isGroup(dstId); + + std::unique_ptr osp; + + if (grp) { + osp = new_unique(lc::tsbk::OSP_GRP_VCH_GRANT_UPD); + + // transmit group voice grant update + osp->setLCO(TSBK_OSP_GRP_VCH_GRANT_UPD); + osp->setDstId(dstId); + osp->setGrpVchId(voiceChData.chId()); + osp->setGrpVchNo(chNo); + } + else { + uint32_t srcId = m_p25->m_affiliations.getGrantedSrcId(dstId); + + osp = new_unique(lc::tsbk::OSP_UU_VCH_GRANT_UPD); + + // 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); + } + + for (int i = 0; i < 3; i++) + m_p25->m_control->writeRF_TSDU_SBF(osp.get(), false, false, false, false); + } + m_rfFrames = 0U; m_rfErrs = 0U; m_rfBits = 1U; @@ -579,7 +649,7 @@ bool Voice::process(uint8_t* data, uint32_t len) } // conventional registration or DVRS support? - if (m_p25->m_enableControl && !m_p25->m_dedicatedControl) { + if ((m_p25->m_enableControl && !m_p25->m_dedicatedControl) || m_p25->m_voiceOnControl) { // per TIA-102.AABD-B transmit RFSS_STS_BCAST every 3 superframes (e.g. every 3 LDU1s) m_vocLDU1Count++; if (m_vocLDU1Count > VOC_LDU1_COUNT) { @@ -1390,7 +1460,7 @@ void Voice::writeNet_LDU1() ::ActivityLog("P25", false, "network %svoice transmission from %u to %s%u", m_netLC.getEncrypted() ? "encrypted " : "", srcId, group ? "TG " : "", dstId); // conventional registration or DVRS support? - if (m_p25->m_enableControl && !m_p25->m_dedicatedControl && !m_p25->m_disableNetworkGrant) { + if (((m_p25->m_enableControl && !m_p25->m_dedicatedControl) || m_p25->m_voiceOnControl) && !m_p25->m_disableNetworkGrant) { uint8_t serviceOptions = (m_netLC.getEmergency() ? 0x80U : 0x00U) + // Emergency Flag (m_netLC.getEncrypted() ? 0x40U : 0x00U) + // Encrypted Flag (m_netLC.getPriority() & 0x07U); // Priority @@ -1426,6 +1496,40 @@ void Voice::writeNet_LDU1() } m_p25->writeRF_Preamble(0, true); + + // if voice on control; insert grant updates before voice traffic + if (m_p25->m_voiceOnControl) { + uint32_t chNo = m_p25->m_affiliations.getGrantedCh(dstId); + ::lookups::VoiceChData voiceChData = m_p25->m_affiliations.getRFChData(chNo); + bool grp = m_p25->m_affiliations.isGroup(dstId); + + std::unique_ptr osp; + + if (grp) { + osp = new_unique(lc::tsbk::OSP_GRP_VCH_GRANT_UPD); + + // transmit group voice grant update + osp->setLCO(TSBK_OSP_GRP_VCH_GRANT_UPD); + osp->setDstId(dstId); + osp->setGrpVchId(voiceChData.chId()); + osp->setGrpVchNo(chNo); + } + else { + uint32_t srcId = m_p25->m_affiliations.getGrantedSrcId(dstId); + + osp = new_unique(lc::tsbk::OSP_UU_VCH_GRANT_UPD); + + // 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); + } + + for (int i = 0; i < 3; i++) + m_p25->m_control->writeRF_TSDU_SBF(osp.get(), false, false, false, true); + } } m_hadVoice = true; @@ -1489,6 +1593,40 @@ void Voice::writeNet_LDU1() } } + // if voice on control; insert group voice channel updates directly after HDU but before LDUs + if (m_p25->m_voiceOnControl) { + uint32_t chNo = m_p25->m_affiliations.getGrantedCh(dstId); + ::lookups::VoiceChData voiceChData = m_p25->m_affiliations.getRFChData(chNo); + bool grp = m_p25->m_affiliations.isGroup(dstId); + + std::unique_ptr osp; + + if (grp) { + osp = new_unique(lc::tsbk::OSP_GRP_VCH_GRANT_UPD); + + // transmit group voice grant update + osp->setLCO(TSBK_OSP_GRP_VCH_GRANT_UPD); + osp->setDstId(dstId); + osp->setGrpVchId(voiceChData.chId()); + osp->setGrpVchNo(chNo); + } + else { + uint32_t srcId = m_p25->m_affiliations.getGrantedSrcId(dstId); + + osp = new_unique(lc::tsbk::OSP_UU_VCH_GRANT_UPD); + + // 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); + } + + for (int i = 0; i < 3; i++) + m_p25->m_control->writeRF_TSDU_SBF(osp.get(), false, false, false, false); + } + uint32_t netId = control.getNetId(); uint32_t sysId = control.getSysId(); @@ -1517,7 +1655,7 @@ void Voice::writeNet_LDU1() } // conventional registration or DVRS support? - if (m_p25->m_enableControl && !m_p25->m_dedicatedControl) { + if ((m_p25->m_enableControl && !m_p25->m_dedicatedControl) || m_p25->m_voiceOnControl) { // per TIA-102.AABD-B transmit RFSS_STS_BCAST every 3 superframes (e.g. every 3 LDU1s) m_vocLDU1Count++; if (m_vocLDU1Count > VOC_LDU1_COUNT) {