From 28bb91fbd2a883669891d6c9354aaaaaa89f8f79 Mon Sep 17 00:00:00 2001 From: Bryan Biedenkapp Date: Thu, 4 Feb 2021 21:19:11 +0000 Subject: [PATCH] fix issue where erroneous CALL_TERM would be transmitted; support SCCB_EXP for when there is more then one CC at a site; --- p25/Control.cpp | 2 +- p25/P25Defines.h | 2 + p25/TrunkPacket.cpp | 97 +++++++++++++++++++++++++++++++++++++++++++-- p25/TrunkPacket.h | 4 ++ p25/VoicePacket.cpp | 14 +++++++ p25/VoicePacket.h | 1 + p25/lc/TSBK.cpp | 40 +++++++++++++++++++ p25/lc/TSBK.h | 8 ++++ 8 files changed, 163 insertions(+), 5 deletions(-) diff --git a/p25/Control.cpp b/p25/Control.cpp index e1f2ff6f..716654bd 100644 --- a/p25/Control.cpp +++ b/p25/Control.cpp @@ -463,7 +463,7 @@ bool Control::writeControlRF() return false; } - if (m_ccSeq == 5U) { + if (m_ccSeq == 6U) { m_ccSeq = 0U; } diff --git a/p25/P25Defines.h b/p25/P25Defines.h index 8c74c642..4fa9803a 100644 --- a/p25/P25Defines.h +++ b/p25/P25Defines.h @@ -120,6 +120,7 @@ namespace p25 const uint8_t P25_IDEN_UP_VU_BW_625K = 0x04U; const uint8_t P25_IDEN_UP_VU_BW_125K = 0x05U; + const uint8_t P25_SVC_CLS_INVALID = 0x00U; const uint8_t P25_SVC_CLS_COMPOSITE = 0x01U; const uint8_t P25_SVC_CLS_VOICE = 0x10U; const uint8_t P25_SVC_CLS_DATA = 0x20U; @@ -275,6 +276,7 @@ namespace p25 const uint8_t TSBK_OSP_SNDCP_CH_GNT = 0x14U; // SNDCP CH GNT - SNDCP Data Channel Grant const uint8_t TSBK_OSP_SNDCP_CH_ANN = 0x16U; // SNDCP CH ANN - SNDCP Data Channel Announcement const uint8_t TSBK_OSP_DENY_RSP = 0x27U; // DENY RSP - Deny Response + const uint8_t TSBK_OSP_SCCB_EXP = 0x29U; // SCCB - Secondary Control Channel Broadcast - Explicit const uint8_t TSBK_OSP_GRP_AFF_Q = 0x2AU; // GRP AFF Q - Group Affiliation Query const uint8_t TSBK_OSP_LOC_REG_RSP = 0x2BU; // LOC REG RSP - Location Registration Response const uint8_t TSBK_OSP_U_REG_CMD = 0x2DU; // U REG CMD - Unit Registration Command diff --git a/p25/TrunkPacket.cpp b/p25/TrunkPacket.cpp index ca2ec31e..916ddb2b 100644 --- a/p25/TrunkPacket.cpp +++ b/p25/TrunkPacket.cpp @@ -682,6 +682,29 @@ bool TrunkPacket::processNetwork(uint8_t* data, uint32_t len, lc::LC& control, d m_adjSiteTable[site.siteId()] = site; m_adjSiteUpdateCnt[site.siteId()] = ADJ_SITE_UPDATE_CNT; + } else { + /* + ** treat same site adjacent site broadcast as a SCCB for this site + */ + // update site table data + SiteData site; + try { + site = m_sccbTable.at(m_netTSBK.getAdjSiteRFSSId()); + } + catch (...) { + site = SiteData(); + } + + if (m_verbose) { + LogMessage(LOG_NET, P25_TSDU_STR ", TSBK_OSP_SCCB_EXP (Secondary Control Channel Broadcast), sysId = $%03X, rfss = $%02X, site = $%02X, chId = %u, chNo = %u", + m_netTSBK.getAdjSiteSysId(), m_netTSBK.getAdjSiteRFSSId(), m_netTSBK.getAdjSiteId(), m_netTSBK.getAdjSiteChnId(), m_netTSBK.getAdjSiteChnNo()); + } + + site.setAdjSite(m_netTSBK.getAdjSiteSysId(), m_netTSBK.getAdjSiteRFSSId(), + m_netTSBK.getAdjSiteId(), m_netTSBK.getAdjSiteChnId(), m_netTSBK.getAdjSiteChnNo()); + + m_sccbTable[site.rfssId()] = site; + m_sccbUpdateCnt[site.rfssId()] = ADJ_SITE_UPDATE_CNT; } return true; @@ -1065,9 +1088,10 @@ void TrunkPacket::clock(uint32_t ms) releaseDstIdGrant(*it, false); } - // clock adjacent site update timers + // clock adjacent site and SCCB update timers m_adjSiteUpdateTimer.clock(ms); if (m_adjSiteUpdateTimer.isRunning() && m_adjSiteUpdateTimer.hasExpired()) { + // update adjacent site data for (auto it = m_adjSiteUpdateCnt.begin(); it != m_adjSiteUpdateCnt.end(); ++it) { uint8_t siteId = it->first; @@ -1085,6 +1109,24 @@ void TrunkPacket::clock(uint32_t ms) m_adjSiteUpdateCnt[siteId] = updateCnt; } + // update SCCB data + for (auto it = m_sccbUpdateCnt.begin(); it != m_sccbUpdateCnt.end(); ++it) { + uint8_t rfssId = it->first; + + uint8_t updateCnt = it->second; + if (updateCnt > 0U) { + updateCnt--; + } + + if (updateCnt == 0U) { + SiteData siteData = m_sccbTable[rfssId]; + LogWarning(LOG_NET, P25_TSDU_STR ", TSBK_OSP_SCCB (Secondary Control Channel Broadcast), no data [FAILED], sysId = $%03X, rfss = $%02X, site = $%02X, chId = %u, chNo = %u", + siteData.sysId(), siteData.rfssId(), siteData.siteId(), siteData.channelId(), siteData.channelNo()); + } + + m_sccbUpdateCnt[rfssId] = updateCnt; + } + m_adjSiteUpdateTimer.setTimeout(m_adjSiteUpdateInterval); m_adjSiteUpdateTimer.start(); } @@ -1236,11 +1278,14 @@ TrunkPacket::TrunkPacket(Control* p25, network::BaseNetwork* network, bool dumpT m_mbfCnt(0U), m_mbfIdenCnt(0U), m_mbfAdjSSCnt(0U), + m_mbfSCCBCnt(0U), m_rfTDULC(), m_netTDULC(), m_voiceChTable(), m_adjSiteTable(), m_adjSiteUpdateCnt(), + m_sccbTable(), + m_sccbUpdateCnt(), m_unitRegTable(), m_grpAffTable(), m_grantChTable(), @@ -1283,6 +1328,9 @@ TrunkPacket::TrunkPacket(Control* p25, network::BaseNetwork* network, bool dumpT m_adjSiteTable.clear(); m_adjSiteUpdateCnt.clear(); + + m_sccbTable.clear(); + m_sccbUpdateCnt.clear(); m_unitRegTable.clear(); m_grpAffTable.clear(); @@ -1352,9 +1400,6 @@ void TrunkPacket::writeRF_ControlData(uint8_t frameCnt, uint8_t n, bool adjSS) switch (n) { - case 0: - queueRF_TSBK_Ctrl_MBF(TSBK_OSP_IDEN_UP); - break; case 1: queueRF_TSBK_Ctrl_MBF(TSBK_OSP_RFSS_STS_BCAST); break; @@ -1368,7 +1413,17 @@ void TrunkPacket::writeRF_ControlData(uint8_t frameCnt, uint8_t n, bool adjSS) // write ADJSS if (adjSS) { queueRF_TSBK_Ctrl_MBF(TSBK_OSP_ADJ_STS_BCAST); + break; + } + case 5: + // write SCCB + if (adjSS) { + queueRF_TSBK_Ctrl_MBF(TSBK_OSP_SCCB_EXP); + break; } + case 0: + default: + queueRF_TSBK_Ctrl_MBF(TSBK_OSP_IDEN_UP); break; } @@ -1803,6 +1858,40 @@ void TrunkPacket::queueRF_TSBK_Ctrl_MBF(uint8_t lco) return; // don't create anything } break; + case TSBK_OSP_SCCB_EXP: + // write SCCB + if (m_sccbTable.size() > 0) { + if (m_mbfSCCBCnt >= m_sccbTable.size()) + m_mbfSCCBCnt = 0U; + + if (m_debug) { + LogMessage(LOG_RF, P25_TSDU_STR ", TSBK_OSP_SCCB_EXP (Secondary Control Channel Broadcast)"); + } + + uint8_t i = 0U; + for (auto it = m_sccbTable.begin(); it != m_sccbTable.end(); ++it) { + // no good very bad way of skipping entries... + if (i != m_mbfSCCBCnt) { + i++; + continue; + } + else { + SiteData site = it->second; + + // transmit SCCB broadcast + m_rfTSBK.setLCO(TSBK_OSP_SCCB_EXP); + m_rfTSBK.setSCCBChnId1(site.channelId()); + m_rfTSBK.setSCCBChnNo(site.channelNo()); + + m_mbfSCCBCnt++; + break; + } + } + } + else { + return; // don't create anything + } + break; case TSBK_OSP_SNDCP_CH_ANN: if (m_debug) { LogMessage(LOG_RF, P25_TSDU_STR ", TSBK_OSP_SNDCP_CH_ANN (SNDCP Channel Announcement)"); diff --git a/p25/TrunkPacket.h b/p25/TrunkPacket.h index ad374248..1a3911eb 100644 --- a/p25/TrunkPacket.h +++ b/p25/TrunkPacket.h @@ -143,6 +143,7 @@ namespace p25 uint8_t m_mbfIdenCnt; uint8_t m_mbfAdjSSCnt; + uint8_t m_mbfSCCBCnt; lc::TDULC m_rfTDULC; lc::TDULC m_netTDULC; @@ -152,6 +153,9 @@ namespace p25 std::unordered_map m_adjSiteTable; std::unordered_map m_adjSiteUpdateCnt; + std::unordered_map m_sccbTable; + std::unordered_map m_sccbUpdateCnt; + std::vector m_unitRegTable; std::unordered_map m_grpAffTable; diff --git a/p25/VoicePacket.cpp b/p25/VoicePacket.cpp index 60470fe1..39fc454a 100644 --- a/p25/VoicePacket.cpp +++ b/p25/VoicePacket.cpp @@ -319,6 +319,8 @@ bool VoicePacket::process(uint8_t* data, uint32_t len) } } + m_hadVoice = true; + m_p25->writeRF_Preamble(); m_p25->m_rfState = RS_RF_AUDIO; @@ -784,6 +786,12 @@ bool VoicePacket::writeEndRF() { if (m_p25->m_netState == RS_NET_IDLE && m_p25->m_rfState == RS_RF_LISTENING) { writeRF_EndOfVoice(); + + // this should have been cleared by writeRF_EndOfVoice; but if it hasn't clear it + // to prevent badness + if (m_hadVoice) { + m_hadVoice = false; + } if (!m_p25->m_ccRunning) { m_p25->m_trunk->writeRF_ControlData(255U, 0U, false); @@ -833,6 +841,7 @@ VoicePacket::VoicePacket(Control* p25, network::BaseNetwork* network, bool debug m_netLDU2(NULL), m_lastDUID(P25_DUID_TDU), m_lastIMBE(NULL), + m_hadVoice(false), m_lastPatchGroup(0U), m_silenceThreshold(124U), m_verbose(verbose), @@ -899,6 +908,10 @@ void VoicePacket::writeNetworkRF(const uint8_t *data, uint8_t duid) /// void VoicePacket::writeRF_EndOfVoice() { + if (!m_hadVoice) { + return; + } + bool grp = m_rfLC.getGroup(); uint32_t srcId = m_rfLC.getSrcId(); uint32_t dstId = m_rfLC.getDstId(); @@ -1089,6 +1102,7 @@ void VoicePacket::writeNet_HDU(const lc::LC& control, const data::LowSpeedData& LogMessage(LOG_NET, P25_HDU_STR ", dstId = %u, algo = $%02X, kid = $%04X", m_netLC.getDstId(), m_netLC.getAlgId(), m_netLC.getKId()); } + m_hadVoice = true; m_p25->m_netState = RS_NET_AUDIO; m_p25->m_netLastDstId = dstId; m_p25->m_netTimeout.start(); diff --git a/p25/VoicePacket.h b/p25/VoicePacket.h index 85b4b350..caf7feef 100644 --- a/p25/VoicePacket.h +++ b/p25/VoicePacket.h @@ -96,6 +96,7 @@ namespace p25 uint8_t* m_netLDU2; uint8_t m_lastDUID; uint8_t* m_lastIMBE; + bool m_hadVoice; uint32_t m_lastPatchGroup; diff --git a/p25/lc/TSBK.cpp b/p25/lc/TSBK.cpp index 7225a2d7..d555b4cb 100644 --- a/p25/lc/TSBK.cpp +++ b/p25/lc/TSBK.cpp @@ -434,6 +434,24 @@ void TSBK::encode(uint8_t * data, bool singleBlock) } } break; + case TSBK_OSP_SCCB_EXP: + tsbkValue = m_siteData.rfssId(); // RF Sub-System ID + tsbkValue = (tsbkValue << 8) + m_siteData.siteId(); // Site ID + + tsbkValue = (tsbkValue << 4) + m_sccbChannelId1; // Channel (T) ID + tsbkValue = (tsbkValue << 12) + m_sccbChannelNo; // Channel (T) Number + tsbkValue = (tsbkValue << 12) + m_sccbChannelId1; // Channel (R) ID + tsbkValue = (tsbkValue << 12) + m_sccbChannelNo; // Channel (R) Number + + if (m_sccbChannelId1 > 0) { + tsbkValue = (tsbkValue << 8) + // System Service Class + (P25_SVC_CLS_COMPOSITE | P25_SVC_CLS_VOICE | P25_SVC_CLS_DATA | P25_SVC_CLS_REG); + } + else { + tsbkValue = (tsbkValue << 8) + // System Service Class + (P25_SVC_CLS_INVALID); + } + break; case TSBK_OSP_GRP_AFF_Q: tsbkValue = 0U; tsbkValue = (tsbkValue << 24) + m_dstId; // Target Radio Address @@ -489,6 +507,28 @@ void TSBK::encode(uint8_t * data, bool singleBlock) tsbkValue = (tsbkValue << 16) + services; // System Services Available tsbkValue = (tsbkValue << 24) + services; // System Services Supported break; + case TSBK_OSP_SCCB: + tsbkValue = m_siteData.rfssId(); // RF Sub-System ID + tsbkValue = (tsbkValue << 8) + m_siteData.siteId(); // Site ID + tsbkValue = (tsbkValue << 16) + m_sccbChannelId1; // SCCB Channel ID 1 + if (m_sccbChannelId1 > 0) { + tsbkValue = (tsbkValue << 8) + // System Service Class + (P25_SVC_CLS_COMPOSITE | P25_SVC_CLS_VOICE | P25_SVC_CLS_DATA | P25_SVC_CLS_REG); + } + else { + tsbkValue = (tsbkValue << 8) + // System Service Class + (P25_SVC_CLS_INVALID); + } + tsbkValue = (tsbkValue << 16) + m_sccbChannelId2; // SCCB Channel ID 2 + if (m_sccbChannelId2 > 0) { + tsbkValue = (tsbkValue << 8) + // System Service Class + (P25_SVC_CLS_COMPOSITE | P25_SVC_CLS_VOICE | P25_SVC_CLS_DATA | P25_SVC_CLS_REG); + } + else { + tsbkValue = (tsbkValue << 8) + // System Service Class + (P25_SVC_CLS_INVALID); + } + break; case TSBK_OSP_RFSS_STS_BCAST: tsbkValue = m_siteData.lra(); // Location Registration Area tsbkValue = (tsbkValue << 4) + diff --git a/p25/lc/TSBK.h b/p25/lc/TSBK.h index 03ddb775..c609bb7f 100644 --- a/p25/lc/TSBK.h +++ b/p25/lc/TSBK.h @@ -146,6 +146,14 @@ namespace p25 /// Adjacent site channel number. __PROPERTY(uint32_t, adjChannelNo, AdjSiteChnNo); + /** SCCB Data */ + /// SCCB channel ID 1. + __PROPERTY(uint8_t, sccbChannelId1, SCCBChnId1); + /// SCCB channel ID 2. + __PROPERTY(uint8_t, sccbChannelId2, SCCBChnId2); + /// Explicit SCCB channel number. + __PROPERTY(uint32_t, sccbChannelNo, SCCBChnNo); + /** Patch Group data */ /// Patch super group ID. __PROPERTY(uint32_t, patchSuperGroupId, PatchSuperGroupId);