diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a3e2d8e5..558c8feb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -55,8 +55,6 @@ file(GLOB dvmhost_SRC "src/p25/data/*.cpp" "src/p25/dfsi/*.h" "src/p25/dfsi/*.cpp" - "src/p25/dfsi/packet/*.h" - "src/p25/dfsi/packet/*.cpp" "src/p25/edac/*.h" "src/p25/edac/*.cpp" "src/p25/lc/*.h" @@ -171,12 +169,6 @@ else () message(CHECK_START "NXDN Digital Mode - disabled") endif (ENABLE_NXDN) -option(ENABLE_DFSI_SUPPORT "Enable P25 DFSI Transport Support" off) -if (ENABLE_DFSI_SUPPORT) - add_definitions(-DENABLE_DFSI_SUPPORT) - message(CHECK_START "P25 DFSI Support - enabled") -endif (ENABLE_DFSI_SUPPORT) - if (ENABLE_TUI_SUPPORT) option(ENABLE_SETUP_TUI "Enable interactive setup TUI" on) if (ENABLE_SETUP_TUI) diff --git a/src/host/Host.cpp b/src/host/Host.cpp index 17df4f49..c7d76c17 100644 --- a/src/host/Host.cpp +++ b/src/host/Host.cpp @@ -596,19 +596,6 @@ int Host::run() g_killed = true; } -#if defined(ENABLE_P25) && defined(ENABLE_DFSI) - // DFSI checks - if (m_useDFSI && m_dmrEnabled) { - ::LogError(LOG_HOST, "Cannot have DMR enabled when using DFSI!"); - g_killed = true; - } - - if (m_useDFSI && m_nxdnEnabled) { - ::LogError(LOG_HOST, "Cannot have NXDN enabled when using DFSI!"); - g_killed = true; - } -#endif // defined(ENABLE_P25) && defined(ENABLE_DFSI) - // P25 CC checks if (m_dmrEnabled && m_p25CtrlChannel) { ::LogError(LOG_HOST, "Cannot have DMR enabled when using dedicated P25 control!"); @@ -2032,12 +2019,6 @@ bool Host::createModem() yaml::Node modemProtocol = modemConf["protocol"]; std::string portType = modemProtocol["type"].as("null"); -#if defined(ENABLE_P25) && defined(ENABLE_DFSI) - m_useDFSI = modemProtocol["dfsi"].as(false); -#else - m_useDFSI = false; -#endif // defined(ENABLE_P25) && defined(ENABLE_DFSI) - yaml::Node uartProtocol = modemProtocol["uart"]; std::string uartPort = uartProtocol["port"].as(); uint32_t uartSpeed = uartProtocol["speed"].as(115200); @@ -2224,10 +2205,6 @@ bool Host::createModem() LogInfo(" P25 FIFO Size: %u bytes", p25FifoLength); LogInfo(" NXDN FIFO Size: %u bytes", nxdnFifoLength); - if (m_useDFSI) { - LogInfo(" Digital Fixed Station Interface: yes"); - } - if (ignoreModemConfigArea) { LogInfo(" Ignore Modem Configuration Area: yes"); } @@ -2253,9 +2230,6 @@ bool Host::createModem() m_modem->setSoftPot(rxCoarse, rxFine, txCoarse, txFine, rssiCoarse, rssiFine); m_modem->setDMRColorCode(m_dmrColorCode); m_modem->setP25NAC(m_p25NAC); -#if defined(ENABLE_P25) && defined(ENABLE_DFSI) - m_modem->setP25DFSI(m_useDFSI); -#endif // defined(ENABLE_P25) && defined(ENABLE_DFSI) } if (m_modemRemote) { diff --git a/src/host/Host.h b/src/host/Host.h index 750d01c0..3a05780f 100644 --- a/src/host/Host.h +++ b/src/host/Host.h @@ -93,7 +93,6 @@ private: bool m_duplex; bool m_fixedMode; - bool m_useDFSI; uint32_t m_timeout; uint32_t m_rfModeHang; diff --git a/src/modem/Modem.cpp b/src/modem/Modem.cpp index 59870f70..8cd9e318 100644 --- a/src/modem/Modem.cpp +++ b/src/modem/Modem.cpp @@ -183,7 +183,6 @@ Modem::Modem(port::IModemPort* port, bool duplex, bool rxInvert, bool txInvert, m_rxDMRQueue2(dmrQueueSize, "Modem RX DMR2"), m_rxP25Queue(p25QueueSize, "Modem RX P25"), m_rxNXDNQueue(nxdnQueueSize, "Modem RX NXDN"), - m_useDFSI(false), m_statusTimer(1000U, 0U, 250U), m_inactivityTimer(1000U, 8U), m_dmrSpace1(0U), @@ -389,15 +388,6 @@ void Modem::setP25NAC(uint32_t nac) m_p25NAC = nac; } -/// -/// Sets the P25 DFSI data mode. -/// -/// -void Modem::setP25DFSI(bool dfsi) -{ - m_useDFSI = dfsi; -} - /// /// Sets the RF receive deviation levels. /// @@ -1129,15 +1119,6 @@ bool Modem::isHotspot() const return m_isHotspot; } -/// -/// Helper to test if the modem is in P25 DFSI data mode. -/// -/// True, if the modem is in P25 DFSI data mode, otherwise false. -bool Modem::isP25DFSI() const -{ - return m_useDFSI; -} - /// /// Flag indicating whether or not the air interface modem is transmitting. /// @@ -1253,11 +1234,6 @@ void Modem::injectDMRFrame1(const uint8_t* data, uint32_t length) assert(data != nullptr); assert(length > 0U); - if (m_useDFSI) { - LogWarning(LOG_MODEM, "Cannot inject DMR Slot 1 Data in DFSI mode"); - return; - } - if (m_trace) Utils::dump(1U, "Injected DMR Slot 1 Data", data, length); @@ -1284,11 +1260,6 @@ void Modem::injectDMRFrame2(const uint8_t* data, uint32_t length) assert(data != nullptr); assert(length > 0U); - if (m_useDFSI) { - LogWarning(LOG_MODEM, "Cannot inject DMr Slot 2 Data in DFSI mode"); - return; - } - if (m_trace) Utils::dump(1U, "Injected DMR Slot 2 Data", data, length); diff --git a/src/modem/Modem.h b/src/modem/Modem.h index ee1c2621..aa343fd7 100644 --- a/src/modem/Modem.h +++ b/src/modem/Modem.h @@ -271,8 +271,6 @@ namespace modem void setDMRColorCode(uint32_t colorCode); /// Sets the P25 NAC. void setP25NAC(uint32_t nac); - /// Sets the P25 DFSI data mode. - void setP25DFSI(bool dfsi); /// Sets the RF receive deviation levels. void setRXLevel(float rxLevel); /// Sets the modem transmit FIFO buffer lengths. @@ -318,9 +316,6 @@ namespace modem /// Helper to test if the modem is a hotspot. bool isHotspot() const; - /// Helper to test if the modem is in P25 DFSI data mode. - bool isP25DFSI() const; - /// Flag indicating whether or not the air interface modem is transmitting. bool hasTX() const; /// Flag indicating whether or not the air interface modem has carrier detect. @@ -493,8 +488,6 @@ namespace modem RingBuffer m_rxP25Queue; RingBuffer m_rxNXDNQueue; - bool m_useDFSI; - Timer m_statusTimer; Timer m_inactivityTimer; diff --git a/src/p25/Control.cpp b/src/p25/Control.cpp index eddec0c4..4d07ed6e 100644 --- a/src/p25/Control.cpp +++ b/src/p25/Control.cpp @@ -32,8 +32,6 @@ #include "p25/P25Defines.h" #include "p25/Control.h" #include "p25/acl/AccessControl.h" -#include "p25/dfsi/packet/DFSITrunk.h" -#include "p25/dfsi/packet/DFSIVoice.h" #include "p25/P25Utils.h" #include "p25/Sync.h" #include "edac/CRC.h" @@ -156,22 +154,9 @@ Control::Control(bool authoritative, uint32_t nac, uint32_t callHang, uint32_t q m_hangCount = callHang * 4U; -#if ENABLE_DFSI_SUPPORT - if (m_modem->isP25DFSI()) { - LogMessage(LOG_P25, "DFSI protocol mode is enabled."); - m_voice = new dfsi::packet::DFSIVoice(this, network, debug, verbose); - m_trunk = new dfsi::packet::DFSITrunk(this, network, dumpTSBKData, debug, verbose); - } - else { - m_voice = new Voice(this, network, debug, verbose); - m_trunk = new Trunk(this, network, dumpTSBKData, debug, verbose); - m_data = new Data(this, network, dumpPDUData, repeatPDU, debug, verbose); - } -#else m_voice = new Voice(this, network, debug, verbose); m_trunk = new Trunk(this, network, dumpTSBKData, debug, verbose); m_data = new Data(this, network, dumpPDUData, repeatPDU, debug, verbose); -#endif } /// @@ -271,12 +256,6 @@ void Control::setOptions(yaml::Node& conf, bool supervisor, const std::string cw m_trunk->m_ctrlTimeDateAnn = control["enableTimeDateAnn"].as(false); m_trunk->m_redundantGrant = control["redundantGrantTransmit"].as(false); -#if ENABLE_DFSI_SUPPORT - if (m_modem->isP25DFSI()) { - m_trunk->m_ctrlTSDUMBF = false; // force SBF for TSDUs when using DFSI - } -#endif - m_voice->m_silenceThreshold = p25Protocol["silenceThreshold"].as(p25::DEFAULT_SILENCE_THRESHOLD); if (m_voice->m_silenceThreshold > MAX_P25_VOICE_ERRORS) { LogWarning(LOG_P25, "Silence threshold > %u, defaulting to %u", p25::MAX_P25_VOICE_ERRORS, p25::DEFAULT_SILENCE_THRESHOLD); @@ -436,12 +415,6 @@ bool Control::processFrame(uint8_t* data, uint32_t len) { assert(data != nullptr); -#if ENABLE_DFSI_SUPPORT - if (m_modem->isP25DFSI()) { - return processDFSI(data, len); - } -#endif - bool sync = data[1U] == 0x01U; if (data[0U] == modem::TAG_LOST) { @@ -958,160 +931,6 @@ void Control::addFrame(const uint8_t* data, uint32_t length, bool net, bool imm) m_txQueue.addData(data, len); } -#if ENABLE_DFSI_SUPPORT -/// -/// Process a DFSI data frame from the RF interface. -/// -/// Buffer containing data frame. -/// Length of data frame. -/// -bool Control::processDFSI(uint8_t* data, uint32_t len) -{ - assert(data != nullptr); - - dfsi::LC dfsiLC = dfsi::LC(); - - if (data[0U] == modem::TAG_LOST && m_rfState == RS_RF_AUDIO) { - if (m_rssi != 0U) { - ::ActivityLog("P25", true, "transmission lost, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm", - float(m_voice->m_rfFrames) / 5.56F, float(m_voice->m_rfErrs * 100U) / float(m_voice->m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount); - } - else { - ::ActivityLog("P25", true, "transmission lost, %.1f seconds, BER: %.1f%%", - float(m_voice->m_rfFrames) / 5.56F, float(m_voice->m_rfErrs * 100U) / float(m_voice->m_rfBits)); - } - - LogMessage(LOG_RF, P25_TDU_STR ", total frames: %d, bits: %d, undecodable LC: %d, errors: %d, BER: %.4f%%", - m_voice->m_rfFrames, m_voice->m_rfBits, m_voice->m_rfUndecodableLC, m_voice->m_rfErrs, float(m_voice->m_rfErrs * 100U) / float(m_voice->m_rfBits)); - - if (m_control) { - m_trunk->releaseDstIdGrant(m_voice->m_rfLC.getDstId(), false); - } - - writeRF_TDU(false); - m_voice->m_lastDUID = P25_DUID_TDU; - m_voice->writeNetworkRF(data + 2U, P25_DUID_TDU); - - m_rfState = RS_RF_LISTENING; - m_rfLastDstId = 0U; - m_rfTGHang.stop(); - - m_tailOnIdle = true; - - m_rfTimeout.stop(); - m_queue.clear(); - - if (m_network != nullptr) - m_network->resetP25(); - - return false; - } - - if (data[0U] == modem::TAG_LOST && m_rfState == RS_RF_DATA) { - m_rfState = RS_RF_LISTENING; - m_rfLastDstId = 0U; - m_rfTGHang.stop(); - - m_tailOnIdle = true; - - m_data->resetRF(); - - m_rfTimeout.stop(); - m_queue.clear(); - - return false; - } - - if (data[0U] == modem::TAG_LOST) { - m_rfState = RS_RF_LISTENING; - - m_voice->resetRF(); - m_data->resetRF(); - - m_trunk->m_rfTSBK = lc::TSBK(m_siteData, m_idenEntry); - - return false; - } - - // Decode the NID - bool valid = dfsiLC.decodeNID(data + 2U); - - if (!valid && m_rfState == RS_RF_LISTENING) - return false; - - uint8_t duid = 0xFFU; // a very invalid DUID - uint8_t frameType = dfsiLC.getFrameType(); - - if (m_debug) { - LogDebug(LOG_RF, "P25 DFSI, rfState = %u, netState = %u, frameType = %u", m_rfState, m_netState, dfsiLC.getFrameType()); - } - - // are we interrupting a running CC? - if (m_ccRunning) { - if (duid != P25_DUID_TSDU) { - g_interruptP25Control = true; - } - } - - // convert DFSI frame-types to DUIDs (this doesn't 100% line up) - if (frameType == dfsi::P25_DFSI_START_STOP || frameType == dfsi::P25_DFSI_VHDR1 || - frameType == dfsi::P25_DFSI_VHDR2) { - duid = P25_DUID_HDU; - } - else if (frameType >= dfsi::P25_DFSI_LDU1_VOICE1 && frameType <= dfsi::P25_DFSI_LDU1_VOICE9) { - duid = P25_DUID_LDU1; - } - else if (frameType >= dfsi::P25_DFSI_LDU2_VOICE10 && frameType <= dfsi::P25_DFSI_LDU2_VOICE18) { - duid = P25_DUID_LDU2; - } - else if (frameType == dfsi::P25_DFSI_TSBK) { - duid = P25_DUID_TSDU; - } - - bool ret = false; - - // handle individual DUIDs - switch (duid) { - case P25_DUID_HDU: - case P25_DUID_LDU1: - case P25_DUID_LDU2: - if (!m_dedicatedControl) - ret = m_voice->process(data, len); - else { - if (m_voiceOnControl && m_trunk->isChBusy(m_siteData.channelNo())) { - ret = m_voice->process(data, len); - } - } - break; - - case P25_DUID_TDU: - case P25_DUID_TDULC: - ret = m_voice->process(data, len); - break; - - case P25_DUID_PDU: - if (!m_dedicatedControl) - ret = m_data->process(data, len); - else { - if (m_voiceOnControl && m_trunk->isChBusy(m_siteData.channelNo())) { - ret = m_data->process(data, len); - } - } - break; - - case P25_DUID_TSDU: - ret = m_trunk->process(data, len); - break; - - default: - LogError(LOG_RF, "P25 unhandled DUID, duid = $%02X", duid); - return false; - } - - return ret; -} -#endif - /// /// Process a data frames from the network. /// @@ -1492,13 +1311,6 @@ void Control::writeRF_Preamble(uint32_t preambleCount, bool force) /// void Control::writeRF_TDU(bool noNetwork) { -#ifdef ENABLE_DFSI_SUPPORT - // for now abort out of this... - if (m_modem->isP25DFSI()) { - return; - } -#endif - uint8_t data[P25_TDU_FRAME_LENGTH_BYTES + 2U]; ::memset(data + 2U, 0x00U, P25_TDU_FRAME_LENGTH_BYTES); diff --git a/src/p25/Control.h b/src/p25/Control.h index 671b67f3..8dac6047 100644 --- a/src/p25/Control.h +++ b/src/p25/Control.h @@ -59,10 +59,8 @@ namespace p25 // --------------------------------------------------------------------------- namespace packet { class HOST_SW_API Voice; } - namespace dfsi { namespace packet { class HOST_SW_API DFSIVoice; } } namespace packet { class HOST_SW_API Data; } namespace packet { class HOST_SW_API Trunk; } - namespace dfsi { namespace packet { class HOST_SW_API DFSITrunk; } } namespace lookups { class HOST_SW_API P25AffiliationLookup; } // --------------------------------------------------------------------------- @@ -143,12 +141,10 @@ namespace p25 private: friend class packet::Voice; - friend class dfsi::packet::DFSIVoice; packet::Voice* m_voice; friend class packet::Data; packet::Data* m_data; friend class packet::Trunk; - friend class dfsi::packet::DFSITrunk; packet::Trunk* m_trunk; friend class lookups::P25AffiliationLookup; @@ -230,11 +226,6 @@ namespace p25 /// Add data frame to the data ring buffer. void addFrame(const uint8_t* data, uint32_t length, bool net = false, bool imm = false); -#if ENABLE_DFSI_SUPPORT - /// Process a DFSI data frame from the RF interface. - bool processDFSI(uint8_t* data, uint32_t len); -#endif - /// Process a data frames from the network. void processNetwork(); /// Helper to process loss of frame stream from modem. diff --git a/src/p25/dfsi/packet/DFSITrunk.cpp b/src/p25/dfsi/packet/DFSITrunk.cpp deleted file mode 100644 index 59c115db..00000000 --- a/src/p25/dfsi/packet/DFSITrunk.cpp +++ /dev/null @@ -1,271 +0,0 @@ -/** -* 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) 2022 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/P25Defines.h" -#include "p25/dfsi/DFSIDefines.h" -#include "p25/packet/Trunk.h" -#include "p25/dfsi/packet/DFSITrunk.h" -#include "p25/P25Utils.h" -#include "p25/Sync.h" -#include "Log.h" -#include "Utils.h" - -using namespace p25; -using namespace p25::dfsi; -using namespace p25::dfsi::packet; - -// --------------------------------------------------------------------------- -// Public Class Members -// --------------------------------------------------------------------------- - -/// -/// Process a data frame from the RF interface. -/// -/// Buffer containing data frame. -/// Length of data frame. -/// Pre-decoded TSBK. -/// -bool DFSITrunk::process(uint8_t* data, uint32_t len, std::unique_ptr preDecodedTSBK) -{ - assert(data != nullptr); - - uint8_t tsbk[P25_TSBK_LENGTH_BYTES]; - ::memset(tsbk, 0x00U, P25_TSBK_LENGTH_BYTES); - - if (!m_p25->m_control) - return false; - - if (preDecodedTSBK != nullptr) { - return Trunk::process(data + 2U, len, std::move(preDecodedTSBK)); - } - else { - if (m_rfDFSILC.decodeTSBK(data + 2U)) { - return Trunk::process(tsbk, P25_TSBK_LENGTH_BYTES, std::unique_ptr(m_rfDFSILC.tsbk())); - } - } - - return false; -} - -// --------------------------------------------------------------------------- -// Protected Class Members -// --------------------------------------------------------------------------- - -/// -/// Initializes a new instance of the DFSITrunk class. -/// -/// Instance of the Control class. -/// Instance of the BaseNetwork class. -/// Flag indicating whether TSBK data is dumped to the log. -/// Flag indicating whether P25 debug is enabled. -/// Flag indicating whether P25 verbose logging is enabled. -DFSITrunk::DFSITrunk(Control* p25, network::BaseNetwork* network, bool dumpTSBKData, bool debug, bool verbose) : - Trunk(p25, network, dumpTSBKData, debug, verbose) -{ - /* stub */ -} - -/// -/// Finalizes a instance of the DFSITrunk class. -/// -DFSITrunk::~DFSITrunk() -{ - /* stub */ -} - -/// -/// Helper to write a P25 TDU w/ link control packet. -/// -/// -/// -void DFSITrunk::writeRF_TDULC(lc::TDULC* lc, bool noNetwork) -{ - // for now this is ignored... -} - -/// -/// Helper to write a single-block P25 TSDU packet. -/// -/// -/// -/// -/// -void DFSITrunk::writeRF_TSDU_SBF(lc::TSBK* tsbk, bool noNetwork, bool clearBeforeWrite, bool force, bool imm) -{ - if (!m_p25->m_control) - return; - - assert(tsbk != nullptr); - - writeRF_DFSI_Start(P25_DFSI_TYPE_TSBK); - - uint8_t data[P25_TSDU_FRAME_LENGTH_BYTES + 2U]; - ::memset(data + 2U, 0x00U, P25_TSDU_FRAME_LENGTH_BYTES); - - m_rfDFSILC.setFrameType(P25_DFSI_TSBK); - m_rfDFSILC.setStartStop(P25_DFSI_START_FLAG); - m_rfDFSILC.setType(P25_DFSI_TYPE_TSBK); - m_rfDFSILC.tsbk(tsbk); - - // Generate Sync - Sync::addP25Sync(data + 2U); - - // Generate NID - m_p25->m_nid.encode(data + 2U, P25_DUID_TSDU); - - // Generate TSBK block - tsbk->setLastBlock(true); // always set last block -- this a Single Block TSDU - tsbk->encode(data + 2U); - - if (m_debug) { - LogDebug(LOG_RF, P25_TSDU_STR " DFSI, lco = $%02X, mfId = $%02X, lastBlock = %u, AIV = %u, EX = %u, srcId = %u, dstId = %u, sysId = $%03X, netId = $%05X", - tsbk->getLCO(), tsbk->getMFId(), tsbk->getLastBlock(), tsbk->getAIV(), tsbk->getEX(), tsbk->getSrcId(), tsbk->getDstId(), - tsbk->getSysId(), tsbk->getNetId()); - - Utils::dump(1U, "!!! *TSDU (SBF) TSBK Block Data", data + P25_PREAMBLE_LENGTH_BYTES + 2U, P25_TSBK_FEC_LENGTH_BYTES); - } - - // Add busy bits - P25Utils::addBusyBits(data + 2U, P25_TSDU_FRAME_LENGTH_BITS, true, false); - - // Set first busy bits to 1,1 - P25Utils::setBusyBits(data + 2U, P25_SS0_START, true, true); - - if (!noNetwork) - writeNetworkRF(tsbk, data + 2U, true); - - // bryanb: hack-o-ramma, for now -- we will force any immediate TSDUs as single-block - if (imm) { - force = true; - } - - if (!force) { - if (clearBeforeWrite) { - m_p25->m_modem->clearP25Frame(); - m_p25->m_txQueue.clear(); - } - } - - ::memset(data + 2U, 0x00U, P25_TSDU_FRAME_LENGTH_BYTES); - - // Generate DFSI TSBK block - m_rfDFSILC.encodeTSBK(data + 2U); - - data[0U] = modem::TAG_DATA; - data[1U] = 0x00U; - - m_p25->addFrame(data, P25_DFSI_TSBK_FRAME_LENGTH_BYTES + 2U); - - writeRF_DSFI_Stop(P25_DFSI_TYPE_TSBK); -} - -/// -/// Helper to write a alternate multi-block trunking PDU packet. -/// -/// -/// -void DFSITrunk::writeRF_TSDU_AMBT(lc::AMBT* ambt, bool clearBeforeWrite) -{ - if (!m_p25->m_control) - return; - - assert(ambt != nullptr); - - // for now this is ignored... -} - -/// -/// Helper to write a network single-block P25 TSDU packet. -/// -/// -void DFSITrunk::writeNet_TSDU(lc::TSBK* tsbk) -{ - assert(tsbk != nullptr); - - uint8_t buffer[P25_DFSI_TSBK_FRAME_LENGTH_BYTES + 2U]; - ::memset(buffer, 0x00U, P25_DFSI_TSBK_FRAME_LENGTH_BYTES + 2U); - - buffer[0U] = modem::TAG_DATA; - buffer[1U] = 0x00U; - - // Regenerate TSDU Data - m_netDFSILC.tsbk(tsbk); - m_netDFSILC.encodeTSBK(buffer + 2U); - - m_p25->addFrame(buffer, P25_DFSI_TSBK_FRAME_LENGTH_BYTES + 2U, true); - - if (m_network != nullptr) - m_network->resetP25(); -} - -/// -/// Helper to write start DFSI data. -/// -/// -void DFSITrunk::writeRF_DFSI_Start(uint8_t type) -{ - uint8_t buffer[P25_DFSI_SS_FRAME_LENGTH_BYTES + 2U]; - ::memset(buffer, 0x00U, P25_DFSI_SS_FRAME_LENGTH_BYTES + 2U); - - // Generate Start/Stop - m_rfDFSILC.setFrameType(P25_DFSI_START_STOP); - m_rfDFSILC.setStartStop(P25_DFSI_START_FLAG); - m_rfDFSILC.setType(type); - - // Generate Identifier Data - m_rfDFSILC.encodeNID(buffer + 2U); - - buffer[0U] = modem::TAG_DATA; - buffer[1U] = 0x00U; - - m_p25->addFrame(buffer, P25_DFSI_SS_FRAME_LENGTH_BYTES + 2U); -} - -/// -/// Helper to write stop DFSI data. -/// -/// -void DFSITrunk::writeRF_DSFI_Stop(uint8_t type) -{ - uint8_t buffer[P25_DFSI_SS_FRAME_LENGTH_BYTES + 2U]; - ::memset(buffer, 0x00U, P25_DFSI_SS_FRAME_LENGTH_BYTES + 2U); - - // Generate Start/Stop - m_rfDFSILC.setFrameType(P25_DFSI_START_STOP); - m_rfDFSILC.setStartStop(P25_DFSI_STOP_FLAG); - m_rfDFSILC.setType(type); - - // Generate Identifier Data - m_rfDFSILC.encodeNID(buffer + 2U); - - buffer[0U] = modem::TAG_EOT; - buffer[1U] = 0x00U; - - // for whatever reason this is almost always sent twice - for (uint8_t i = 0; i < 2;i ++) { - m_p25->addFrame(buffer, P25_DFSI_SS_FRAME_LENGTH_BYTES + 2U); - } -} diff --git a/src/p25/dfsi/packet/DFSITrunk.h b/src/p25/dfsi/packet/DFSITrunk.h deleted file mode 100644 index a722ca43..00000000 --- a/src/p25/dfsi/packet/DFSITrunk.h +++ /dev/null @@ -1,93 +0,0 @@ -/** -* 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) 2022 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_DFSI_PACKET_TRUNK_H__) -#define __P25_DFSI_PACKET_TRUNK_H__ - -#include "Defines.h" -#include "p25/dfsi/LC.h" -#include "p25/Control.h" -#include "network/BaseNetwork.h" - -namespace p25 -{ - // --------------------------------------------------------------------------- - // Class Prototypes - // --------------------------------------------------------------------------- - - namespace packet { class HOST_SW_API Trunk; } - class HOST_SW_API Control; - - namespace dfsi - { - namespace packet - { - // --------------------------------------------------------------------------- - // Class Declaration - // This class implements handling logic for P25 trunking packets using - // the DFSI protocol instead of the P25 OTA protocol. - // --------------------------------------------------------------------------- - - class HOST_SW_API DFSITrunk : public p25::packet::Trunk { - public: - /// Process a data frame from the RF interface. - bool process(uint8_t* data, uint32_t len, std::unique_ptr preDecodedTSBK = nullptr) override; - - protected: - LC m_rfDFSILC; - LC m_netDFSILC; - - /// Initializes a new instance of the DFSITrunk class. - DFSITrunk(Control* p25, network::BaseNetwork* network, bool dumpTSBKData, bool debug, bool verbose); - /// Finalizes a instance of the DFSITrunk class. - virtual ~DFSITrunk(); - - /// Helper to write a P25 TDU w/ link control packet. - void writeRF_TDULC(lc::TDULC* lc, bool noNetwork) override; - - /// Helper to write a single-block P25 TSDU packet. - void writeRF_TSDU_SBF(lc::TSBK* tsbk, bool noNetwork, bool clearBeforeWrite = false, bool force = false, bool imm = false) override; - /// Helper to write a alternate multi-block trunking PDU packet. - void writeRF_TSDU_AMBT(lc::AMBT* ambt, bool clearBeforeWrite = false) override; - - /// Helper to write a network P25 TDU w/ link control packet. - //void writeNet_TDULC(lc::TDULC lc) override; - /// Helper to write a network single-block P25 TSDU packet. - void writeNet_TSDU(lc::TSBK* tsbk) override; - - /// Helper to write start DFSI data. - void writeRF_DFSI_Start(uint8_t type); - /// Helper to write stop DFSI data. - void writeRF_DSFI_Stop(uint8_t type); - - private: - friend class packet::DFSIVoice; - friend class p25::Control; - }; - } // namespace packet - } // namespace dfsi -} // namespace p25 - -#endif // __P25_DFSI_PACKET_TRUNK_H__ diff --git a/src/p25/dfsi/packet/DFSIVoice.cpp b/src/p25/dfsi/packet/DFSIVoice.cpp deleted file mode 100644 index f71f4783..00000000 --- a/src/p25/dfsi/packet/DFSIVoice.cpp +++ /dev/null @@ -1,1272 +0,0 @@ -/** -* 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 -* -*/ -// -// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost) -// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0) -// -/* -* Copyright (C) 2022 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/P25Defines.h" -#include "p25/acl/AccessControl.h" -#include "p25/dfsi/DFSIDefines.h" -#include "p25/packet/Trunk.h" -#include "p25/packet/Voice.h" -#include "p25/dfsi/packet/DFSIVoice.h" -#include "p25/P25Utils.h" -#include "p25/Sync.h" -#include "HostMain.h" -#include "Log.h" -#include "Utils.h" - -using namespace p25; -using namespace p25::dfsi; -using namespace p25::dfsi::packet; - -// --------------------------------------------------------------------------- -// Constants -// --------------------------------------------------------------------------- - -const uint32_t VOC_LDU1_COUNT = 3U; - -// --------------------------------------------------------------------------- -// Public Class Members -// --------------------------------------------------------------------------- - -/// -/// Resets the data states for the RF interface. -/// -void DFSIVoice::resetRF() -{ - Voice::resetRF(); - - LC lc = LC(); - m_rfDFSILC = lc; -} - -/// -/// Resets the data states for the network. -/// -void DFSIVoice::resetNet() -{ - Voice::resetNet(); - - LC lc = LC(); - m_netDFSILC = lc; -} - -/// -/// Process a data frame from the RF interface. -/// -/// Buffer containing data frame. -/// Length of data frame. -/// -bool DFSIVoice::process(uint8_t* data, uint32_t len) -{ - assert(data != nullptr); - - bool valid = m_rfDFSILC.decodeNID(data + 2U); - - if (m_p25->m_rfState == RS_RF_LISTENING && !valid) - return false; - - uint8_t frameType = m_rfDFSILC.getFrameType(); - if (frameType == P25_DFSI_VHDR2) { - if (m_p25->m_rfState == RS_RF_LISTENING) { - if (!m_p25->m_dedicatedControl) { - m_p25->m_modem->clearP25Frame(); - } - m_p25->m_txQueue.clear(); - resetRF(); - resetNet(); - } - - if (m_p25->m_rfState == RS_RF_LISTENING || m_p25->m_rfState == RS_RF_AUDIO) { - resetRF(); - resetNet(); - - bool ret = m_rfDFSILC.decodeVHDR2(data + 2U); - if (!ret) { - LogWarning(LOG_RF, P25_HDU_STR " DFSI, undecodable LC"); - m_rfUndecodableLC++; - return false; - } - - m_rfLC = lc::LC(*m_rfDFSILC.control()); - - if (m_verbose) { - LogMessage(LOG_RF, P25_HDU_STR " DFSI, HDU_BSDWNACT, dstId = %u, algo = $%02X, kid = $%04X", m_rfLC.getDstId(), m_rfLC.getAlgId(), m_rfLC.getKId()); - } - - // don't process RF frames if the network isn't in a idle state and the RF destination is the network destination - if (m_p25->m_netState != RS_NET_IDLE && m_rfLC.getDstId() == m_p25->m_netLastDstId) { - LogWarning(LOG_RF, "Traffic collision detect, preempting new RF traffic to existing network traffic!"); - resetRF(); - return false; - } - - // stop network frames from processing -- RF wants to transmit on a different talkgroup - if (m_p25->m_netState != RS_NET_IDLE) { - LogWarning(LOG_RF, "Traffic collision detect, preempting existing network traffic to new RF traffic, rfDstId = %u, netDstId = %u", m_rfLC.getDstId(), - m_p25->m_netLastDstId); - resetNet(); - } - - m_p25->m_rfTGHang.start(); - m_p25->m_rfLastDstId = m_rfLC.getDstId(); - - m_rfLastHDU = m_rfLC; - } - - return true; - } - else if (frameType >= P25_DFSI_LDU1_VOICE1 && frameType <= P25_DFSI_LDU1_VOICE9) { - uint8_t n = 10U; - switch (frameType) { - case P25_DFSI_LDU1_VOICE1: - n = 10U; - break; - case P25_DFSI_LDU1_VOICE2: - n = 26U; - break; - case P25_DFSI_LDU1_VOICE3: - n = 55U; - break; - case P25_DFSI_LDU1_VOICE4: - n = 80U; - break; - case P25_DFSI_LDU1_VOICE5: - n = 105U; - break; - case P25_DFSI_LDU1_VOICE6: - n = 130U; - break; - case P25_DFSI_LDU1_VOICE7: - n = 155U; - break; - case P25_DFSI_LDU1_VOICE8: - n = 180U; - break; - case P25_DFSI_LDU1_VOICE9: - n = 204U; - break; - } - - if (m_rfDFSILC.decodeLDU1(data + 2U, m_dfsiLDU1 + n)) { - // if this is the last LDU1 frame process the full LDU1 - if (frameType == P25_DFSI_LDU1_VOICE9) { - bool alreadyDecoded = false; - m_lastDUID = P25_DUID_LDU1; - - if (m_p25->m_rfState == RS_RF_LISTENING) { - // if this is a late entry call, clear states - if (m_rfLastHDU.getDstId() == 0U) { - if (!m_p25->m_dedicatedControl) { - m_p25->m_modem->clearP25Frame(); - } - m_p25->m_txQueue.clear(); - resetRF(); - resetNet(); - } - - if (m_p25->m_control) { - if (!m_p25->m_ccRunning && m_p25->m_voiceOnControl) { - m_p25->m_trunk->writeRF_ControlData(255U, 0U, false); - } - } - - lc::LC lc = lc::LC(*m_rfDFSILC.control()); - - uint32_t srcId = lc.getSrcId(); - uint32_t dstId = lc.getDstId(); - bool group = lc.getGroup(); - bool encrypted = lc.getEncrypted(); - - alreadyDecoded = true; - - // don't process RF frames if the network isn't in a idle state and the RF destination is the network destination - if (m_p25->m_netState != RS_NET_IDLE && dstId == m_p25->m_netLastDstId) { - LogWarning(LOG_RF, "Traffic collision detect, preempting new RF traffic to existing network traffic!"); - resetRF(); - ::memset(m_dfsiLDU1, 0x00U, 9U * 25U); - return false; - } - - // stop network frames from processing -- RF wants to transmit on a different talkgroup - if (m_p25->m_netState != RS_NET_IDLE) { - if (m_netLC.getSrcId() == srcId && m_p25->m_netLastDstId == dstId) { - LogWarning(LOG_RF, "Traffic collision detect, preempting new RF traffic to existing RF traffic (Are we in a voting condition?), rfSrcId = %u, rfDstId = %u, netSrcId = %u, netDstId = %u", srcId, dstId, - m_netLC.getSrcId(), m_p25->m_netLastDstId); - resetRF(); - ::memset(m_dfsiLDU1, 0x00U, 9U * 25U); - return false; - } - else { - LogWarning(LOG_RF, "Traffic collision detect, preempting existing network traffic to new RF traffic, rfDstId = %u, netDstId = %u", dstId, - m_p25->m_netLastDstId); - resetNet(); - } - } - - // validate the source RID - if (!acl::AccessControl::validateSrcId(srcId)) { - if (m_lastRejectId == 0U || m_lastRejectId != srcId) { - LogWarning(LOG_RF, P25_HDU_STR " denial, RID rejection, srcId = %u", srcId); - if (m_p25->m_control) { - m_p25->m_trunk->writeRF_TSDU_Deny(srcId, dstId, P25_DENY_RSN_REQ_UNIT_NOT_VALID, (group ? TSBK_IOSP_GRP_VCH : TSBK_IOSP_UU_VCH)); - m_p25->m_trunk->denialInhibit(srcId); - } - - ::ActivityLog("P25", true, "RF voice rejection from %u to %s%u ", srcId, group ? "TG " : "", dstId); - m_lastRejectId = srcId; - } - - m_p25->m_rfLastDstId = 0U; - m_p25->m_rfTGHang.stop(); - m_p25->m_rfState = RS_RF_REJECTED; - ::memset(m_dfsiLDU1, 0x00U, 9U * 25U); - return false; - } - - // is this a group or individual operation? - if (!group) { - // validate the target RID - if (!acl::AccessControl::validateSrcId(dstId)) { - if (m_lastRejectId == 0 || m_lastRejectId != dstId) { - LogWarning(LOG_RF, P25_HDU_STR " denial, RID rejection, dstId = %u", dstId); - if (m_p25->m_control) { - m_p25->m_trunk->writeRF_TSDU_Deny(srcId, dstId, P25_DENY_RSN_TGT_UNIT_NOT_VALID, TSBK_IOSP_UU_VCH); - } - - ::ActivityLog("P25", true, "RF voice rejection from %u to %s%u ", srcId, group ? "TG " : "", dstId); - m_lastRejectId = dstId; - } - - m_p25->m_rfLastDstId = 0U; - m_p25->m_rfTGHang.stop(); - m_p25->m_rfState = RS_RF_REJECTED; - ::memset(m_dfsiLDU1, 0x00U, 9U * 25U); - return false; - } - } - else { - // validate the target ID, if the target is a talkgroup - if (!acl::AccessControl::validateTGId(dstId)) { - if (m_lastRejectId == 0 || m_lastRejectId != dstId) { - LogWarning(LOG_RF, P25_HDU_STR " denial, TGID rejection, dstId = %u", dstId); - if (m_p25->m_control) { - m_p25->m_trunk->writeRF_TSDU_Deny(srcId, dstId, P25_DENY_RSN_TGT_GROUP_NOT_VALID, TSBK_IOSP_GRP_VCH); - } - - ::ActivityLog("P25", true, "RF voice rejection from %u to %s%u ", srcId, group ? "TG " : "", dstId); - m_lastRejectId = dstId; - } - - m_p25->m_rfLastDstId = 0U; - m_p25->m_rfTGHang.stop(); - m_p25->m_rfState = RS_RF_REJECTED; - ::memset(m_dfsiLDU1, 0x00U, 9U * 25U); - return false; - } - } - - // verify the source RID is affiliated to the group TGID; only if control data - // is supported - if (group && m_p25->m_control) { - if (!m_p25->m_affiliations.isGroupAff(srcId, dstId) && m_p25->m_trunk->m_verifyAff) { - if (m_lastRejectId == 0 || m_lastRejectId != srcId) { - LogWarning(LOG_RF, P25_HDU_STR " denial, RID not affiliated to TGID, srcId = %u, dstId = %u", srcId, dstId); - m_p25->m_trunk->writeRF_TSDU_Deny(srcId, dstId, P25_DENY_RSN_REQ_UNIT_NOT_AUTH, TSBK_IOSP_GRP_VCH); - m_p25->m_trunk->writeRF_TSDU_U_Reg_Cmd(srcId); - - ::ActivityLog("P25", true, "RF voice rejection from %u to %s%u ", srcId, group ? "TG " : "", dstId); - m_lastRejectId = srcId; - } - - m_p25->m_rfLastDstId = 0U; - m_p25->m_rfTGHang.stop(); - m_p25->m_rfState = RS_RF_REJECTED; - ::memset(m_dfsiLDU1, 0x00U, 9U * 25U); - return false; - } - } - - m_rfLC = lc; - m_rfLastLDU1 = m_rfLC; - - m_lastRejectId = 0U; - ::ActivityLog("P25", true, "RF %svoice transmission from %u to %s%u", encrypted ? "encrypted " : "", srcId, group ? "TG " : "", dstId); - - uint8_t serviceOptions = (m_rfLC.getEmergency() ? 0x80U : 0x00U) + // Emergency Flag - (m_rfLC.getEncrypted() ? 0x40U : 0x00U) + // Encrypted Flag - (m_rfLC.getPriority() & 0x07U); // Priority - - if (m_p25->m_control) { - // if the group wasn't granted out -- explicitly grant the group - if (!m_p25->m_affiliations.isGranted(dstId)) { - if (m_p25->m_legacyGroupGrnt) { - // are we auto-registering legacy radios to groups? - if (m_p25->m_legacyGroupReg && group) { - if (!m_p25->m_affiliations.isGroupAff(srcId, dstId)) { - if (!m_p25->m_trunk->writeRF_TSDU_Grp_Aff_Rsp(srcId, dstId)) { - ::memset(m_dfsiLDU1, 0x00U, 9U * 25U); - return false; - } - } - } - - if (!m_p25->m_trunk->writeRF_TSDU_Grant(srcId, dstId, serviceOptions, group)) { - ::memset(m_dfsiLDU1, 0x00U, 9U * 25U); - return false; - } - } - else { - ::memset(m_dfsiLDU1, 0x00U, 9U * 25U); - return false; - } - } - } - - // single-channel trunking or voice on control support? - if (m_p25->m_control && m_p25->m_voiceOnControl) { - m_p25->m_trunk->writeRF_TSDU_Grant(srcId, dstId, serviceOptions, group, true); - } - - m_hadVoice = true; - - m_p25->m_rfState = RS_RF_AUDIO; - - m_p25->m_rfTGHang.start(); - m_p25->m_rfLastDstId = dstId; - - // make sure we actually got a HDU -- otherwise treat the call as a late entry - if (m_rfLastHDU.getDstId() != 0U) { - // copy destination and encryption parameters from the last HDU received (if possible) - if (m_rfLC.getDstId() != m_rfLastHDU.getDstId()) { - m_rfLC.setDstId(m_rfLastHDU.getDstId()); - } - - m_rfLC.setAlgId(m_rfLastHDU.getAlgId()); - m_rfLC.setKId(m_rfLastHDU.getKId()); - - uint8_t mi[P25_MI_LENGTH_BYTES]; - m_rfLastHDU.getMI(mi); - m_rfLC.setMI(mi); - - uint8_t buffer[P25_HDU_FRAME_LENGTH_BYTES + 2U]; - ::memset(buffer, 0x00U, P25_HDU_FRAME_LENGTH_BYTES + 2U); - - // Generate Sync - Sync::addP25Sync(buffer + 2U); - - // Generate NID - m_p25->m_nid.encode(buffer + 2U, P25_DUID_HDU); - - // Generate HDU - m_rfLC.encodeHDU(buffer + 2U); - - // Add busy bits - P25Utils::addBusyBits(buffer + 2U, P25_HDU_FRAME_LENGTH_BITS, false, true); - - writeNetwork(buffer, P25_DUID_HDU); - - if (m_verbose) { - LogMessage(LOG_RF, P25_HDU_STR " DFSI, dstId = %u, algo = $%02X, kid = $%04X", m_rfLC.getDstId(), m_rfLC.getAlgId(), m_rfLC.getKId()); - } - } - else { - LogWarning(LOG_RF, P25_HDU_STR " DFSI, not transmitted; possible late entry, dstId = %u, algo = $%02X, kid = $%04X", m_rfLastHDU.getDstId(), m_rfLastHDU.getAlgId(), m_rfLastHDU.getKId()); - } - - m_rfFrames = 0U; - m_rfErrs = 0U; - m_rfBits = 1U; - m_rfUndecodableLC = 0U; - m_vocLDU1Count = 0U; - m_p25->m_rfTimeout.start(); - m_lastDUID = P25_DUID_HDU; - - m_rfLastHDU = lc::LC(); - } - - if (m_p25->m_rfState == RS_RF_AUDIO) { - if (!alreadyDecoded) { - m_rfLC = lc::LC(*m_rfDFSILC.control()); - m_rfLastLDU1 = m_rfLC; - } - - if (m_p25->m_control) { - m_p25->m_affiliations.touchGrant(m_rfLC.getDstId()); - m_p25->notifyCC_TouchGrant(m_rfLC.getDstId()); - } - - // single-channel trunking or voice on control support? - if (m_p25->m_control && 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) { - m_vocLDU1Count = 0U; - m_rfLC.setLCO(LC_RFSS_STS_BCAST); - } - } - - uint8_t buffer[P25_LDU_FRAME_LENGTH_BYTES + 2U]; - ::memset(buffer, 0x00U, P25_LDU_FRAME_LENGTH_BYTES + 2U); - - // Generate Sync - Sync::addP25Sync(buffer + 2U); - - // Generate NID - m_p25->m_nid.encode(buffer + 2U, P25_DUID_LDU1); - - // Generate LDU1 Data - m_rfLC.encodeLDU1(buffer + 2U); - - // Generate Low Speed Data - m_rfLSD.process(buffer + 2U); - - insertMissingAudio(m_dfsiLDU1); - - // Add the Audio - m_audio.encode(buffer + 2U, m_dfsiLDU1 + 10U, 0U); - m_audio.encode(buffer + 2U, m_dfsiLDU1 + 26U, 1U); - m_audio.encode(buffer + 2U, m_dfsiLDU1 + 55U, 2U); - m_audio.encode(buffer + 2U, m_dfsiLDU1 + 80U, 3U); - m_audio.encode(buffer + 2U, m_dfsiLDU1 + 105U, 4U); - m_audio.encode(buffer + 2U, m_dfsiLDU1 + 130U, 5U); - m_audio.encode(buffer + 2U, m_dfsiLDU1 + 155U, 6U); - m_audio.encode(buffer + 2U, m_dfsiLDU1 + 180U, 7U); - m_audio.encode(buffer + 2U, m_dfsiLDU1 + 204U, 8U); - - m_rfBits += 1233U; - m_rfFrames++; - - // Add busy bits - P25Utils::addBusyBits(buffer + 2U, P25_LDU_FRAME_LENGTH_BITS, false, true); - - writeNetwork(buffer + 2U, P25_DUID_LDU1); - - if (m_verbose) { - LogMessage(LOG_RF, P25_LDU1_STR " DFSI, audio, srcId = %u, dstId = %u, group = %u, emerg = %u, encrypt = %u, prio = %u", - m_rfLC.getSrcId(), m_rfLC.getDstId(), m_rfLC.getGroup(), m_rfLC.getEmergency(), m_rfLC.getEncrypted(), m_rfLC.getPriority()); - } - - ::memset(m_dfsiLDU1, 0x00U, 9U * 25U); - return true; - } - } - } - } - else if (frameType >= P25_DFSI_LDU2_VOICE10 && frameType <= P25_DFSI_LDU2_VOICE18) { - uint8_t n = 10U; - switch (frameType) { - case P25_DFSI_LDU2_VOICE10: - n = 10U; - break; - case P25_DFSI_LDU2_VOICE11: - n = 26U; - break; - case P25_DFSI_LDU2_VOICE12: - n = 55U; - break; - case P25_DFSI_LDU2_VOICE13: - n = 80U; - break; - case P25_DFSI_LDU2_VOICE14: - n = 105U; - break; - case P25_DFSI_LDU2_VOICE15: - n = 130U; - break; - case P25_DFSI_LDU2_VOICE16: - n = 155U; - break; - case P25_DFSI_LDU2_VOICE17: - n = 180U; - break; - case P25_DFSI_LDU2_VOICE18: - n = 204U; - break; - } - - if (m_rfDFSILC.decodeLDU2(data + 2U, m_dfsiLDU2 + n)) { - // if this is the last LDU2 frame process the full LDU2 - if (frameType == P25_DFSI_LDU2_VOICE18) { - m_lastDUID = P25_DUID_LDU2; - - if (m_p25->m_rfState == RS_RF_LISTENING) { - ::memset(m_dfsiLDU2, 0x00U, 9U * 25U); - return false; - } - else if (m_p25->m_rfState == RS_RF_AUDIO) { - m_rfLC = lc::LC(*m_rfDFSILC.control()); - m_rfLastLDU2 = m_rfLC; - - uint8_t buffer[P25_LDU_FRAME_LENGTH_BYTES + 2U]; - ::memset(buffer, 0x00U, P25_LDU_FRAME_LENGTH_BYTES + 2U); - - // Generate Sync - Sync::addP25Sync(buffer + 2U); - - // Generate NID - m_p25->m_nid.encode(buffer + 2U, P25_DUID_LDU2); - - // Generate LDU2 data - m_rfLC.encodeLDU2(buffer + 2U); - - // Generate Low Speed Data - m_rfLSD.process(buffer + 2U); - - insertMissingAudio(m_dfsiLDU2); - - // Add the Audio - m_audio.encode(buffer + 2U, m_dfsiLDU2 + 10U, 0U); - m_audio.encode(buffer + 2U, m_dfsiLDU2 + 26U, 1U); - m_audio.encode(buffer + 2U, m_dfsiLDU2 + 55U, 2U); - m_audio.encode(buffer + 2U, m_dfsiLDU2 + 80U, 3U); - m_audio.encode(buffer + 2U, m_dfsiLDU2 + 105U, 4U); - m_audio.encode(buffer + 2U, m_dfsiLDU2 + 130U, 5U); - m_audio.encode(buffer + 2U, m_dfsiLDU2 + 155U, 6U); - m_audio.encode(buffer + 2U, m_dfsiLDU2 + 180U, 7U); - m_audio.encode(buffer + 2U, m_dfsiLDU2 + 204U, 8U); - - m_rfBits += 1233U; - m_rfFrames++; - - // Add busy bits - P25Utils::addBusyBits(buffer + 2U, P25_LDU_FRAME_LENGTH_BITS, false, true); - - writeNetwork(buffer + 2U, P25_DUID_LDU2); - - if (m_verbose) { - LogMessage(LOG_RF, P25_LDU2_STR " DFSI, audio, algo = $%02X, kid = $%04X", - m_rfLC.getAlgId(), m_rfLC.getKId()); - } - - ::memset(m_dfsiLDU2, 0x00U, 9U * 25U); - return true; - } - } - } - } - else if (frameType == P25_DFSI_START_STOP) { - if (m_rfDFSILC.getType() == P25_DFSI_TYPE_VOICE && m_rfDFSILC.getStartStop() == P25_DFSI_STOP_FLAG) { - if (!m_p25->m_control) { - m_p25->m_affiliations.releaseGrant(m_rfLC.getDstId(), false); - m_p25->notifyCC_ReleaseGrant(m_rfLC.getDstId()); - } - - uint8_t data[P25_TDU_FRAME_LENGTH_BYTES + 2U]; - ::memset(data + 2U, 0x00U, P25_TDU_FRAME_LENGTH_BYTES); - - // Generate Sync - Sync::addP25Sync(data + 2U); - - // Generate NID - m_p25->m_nid.encode(data + 2U, P25_DUID_TDU); - - // Add busy bits - P25Utils::addBusyBits(data + 2U, P25_TDU_FRAME_LENGTH_BITS, true, true); - - writeNetwork(data + 2U, P25_DUID_TDU); - - m_lastDUID = P25_DUID_TDU; - - m_p25->m_rfTimeout.stop(); - - if (m_p25->m_rfState == RS_RF_AUDIO) { - if (m_p25->m_rssi != 0U) { - ::ActivityLog("P25", true, "RF end of transmission, %.1f seconds, BER: %.1f%%, RSSI : -%u / -%u / -%u dBm", - float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits), m_p25->m_minRSSI, m_p25->m_maxRSSI, - m_p25->m_aveRSSI / m_p25->m_rssiCount); - } - else { - ::ActivityLog("P25", true, "RF end of transmission, %.1f seconds, BER: %.1f%%", - float(m_rfFrames) / 5.56F, float(m_rfErrs * 100U) / float(m_rfBits)); - } - - LogMessage(LOG_RF, P25_TDU_STR " DFSI, total frames: %d, bits: %d, undecodable LC: %d, errors: %d, BER: %.4f%%", - m_rfFrames, m_rfBits, m_rfUndecodableLC, m_rfErrs, float(m_rfErrs * 100U) / float(m_rfBits)); - - if (m_p25->m_dedicatedControl) { - m_p25->m_tailOnIdle = false; - writeRF_EndOfVoice(); - } - else { - m_p25->m_tailOnIdle = true; - } - } - - m_p25->m_rfState = RS_RF_LISTENING; - return true; - } - } - else { - LogError(LOG_RF, "P25 unhandled DFSI frame type, frameType = $%02X", frameType); - } - - return false; -} - -/// -/// Process a data frame from the network. -/// -/// Buffer containing data frame. -/// Length of data frame. -/// Link Control Data. -/// Low Speed Data. -/// Data Unit ID. -/// Network Frame Type. -/// -bool DFSIVoice::processNetwork(uint8_t* data, uint32_t len, lc::LC& control, data::LowSpeedData& lsd, uint8_t& duid, uint8_t& frameType) -{ - uint32_t count = 0U; - - switch (duid) { - case P25_DUID_LDU1: - if ((data[0U] == dfsi::P25_DFSI_LDU1_VOICE1) && (data[22U] == dfsi::P25_DFSI_LDU1_VOICE2) && - (data[36U] == dfsi::P25_DFSI_LDU1_VOICE3) && (data[53U] == dfsi::P25_DFSI_LDU1_VOICE4) && - (data[70U] == dfsi::P25_DFSI_LDU1_VOICE5) && (data[87U] == dfsi::P25_DFSI_LDU1_VOICE6) && - (data[104U] == dfsi::P25_DFSI_LDU1_VOICE7) && (data[121U] == dfsi::P25_DFSI_LDU1_VOICE8) && - (data[138U] == dfsi::P25_DFSI_LDU1_VOICE9)) { - - m_dfsiLC = dfsi::LC(control, lsd); - - m_dfsiLC.setFrameType(dfsi::P25_DFSI_LDU1_VOICE1); - m_dfsiLC.decodeLDU1(data + count, m_netLDU1 + 10U); - count += 22U; - - m_dfsiLC.setFrameType(dfsi::P25_DFSI_LDU1_VOICE2); - m_dfsiLC.decodeLDU1(data + count, m_netLDU1 + 26U); - count += 14U; - - m_dfsiLC.setFrameType(dfsi::P25_DFSI_LDU1_VOICE3); - m_dfsiLC.decodeLDU1(data + count, m_netLDU1 + 55U); - count += 17U; - - m_dfsiLC.setFrameType(dfsi::P25_DFSI_LDU1_VOICE4); - m_dfsiLC.decodeLDU1(data + count, m_netLDU1 + 80U); - count += 17U; - - m_dfsiLC.setFrameType(dfsi::P25_DFSI_LDU1_VOICE5); - m_dfsiLC.decodeLDU1(data + count, m_netLDU1 + 105U); - count += 17U; - - m_dfsiLC.setFrameType(dfsi::P25_DFSI_LDU1_VOICE6); - m_dfsiLC.decodeLDU1(data + count, m_netLDU1 + 130U); - count += 17U; - - m_dfsiLC.setFrameType(dfsi::P25_DFSI_LDU1_VOICE7); - m_dfsiLC.decodeLDU1(data + count, m_netLDU1 + 155U); - count += 17U; - - m_dfsiLC.setFrameType(dfsi::P25_DFSI_LDU1_VOICE8); - m_dfsiLC.decodeLDU1(data + count, m_netLDU1 + 180U); - count += 17U; - - m_dfsiLC.setFrameType(dfsi::P25_DFSI_LDU1_VOICE9); - m_dfsiLC.decodeLDU1(data + count, m_netLDU1 + 204U); - count += 16U; - - m_netLastLDU1 = control; - - if (m_p25->m_netState == RS_NET_IDLE) { - // are we interrupting a running CC? - if (m_p25->m_ccRunning) { - m_p25->m_ccHalted = true; - } - } - - checkNet_LDU2(); - if (m_p25->m_netState != RS_NET_IDLE) { - writeNet_LDU1(); - } - } - break; - case P25_DUID_LDU2: - if ((data[0U] == dfsi::P25_DFSI_LDU2_VOICE10) && (data[22U] == dfsi::P25_DFSI_LDU2_VOICE11) && - (data[36U] == dfsi::P25_DFSI_LDU2_VOICE12) && (data[53U] == dfsi::P25_DFSI_LDU2_VOICE13) && - (data[70U] == dfsi::P25_DFSI_LDU2_VOICE14) && (data[87U] == dfsi::P25_DFSI_LDU2_VOICE15) && - (data[104U] == dfsi::P25_DFSI_LDU2_VOICE16) && (data[121U] == dfsi::P25_DFSI_LDU2_VOICE17) && - (data[138U] == dfsi::P25_DFSI_LDU2_VOICE18)) { - m_dfsiLC.setFrameType(dfsi::P25_DFSI_LDU2_VOICE10); - m_dfsiLC.decodeLDU2(data + count, m_netLDU2 + 10U); - count += 22U; - - m_dfsiLC.setFrameType(dfsi::P25_DFSI_LDU2_VOICE11); - m_dfsiLC.decodeLDU2(data + count, m_netLDU2 + 26U); - count += 14U; - - m_dfsiLC.setFrameType(dfsi::P25_DFSI_LDU2_VOICE12); - m_dfsiLC.decodeLDU2(data + count, m_netLDU2 + 55U); - count += 17U; - - m_dfsiLC.setFrameType(dfsi::P25_DFSI_LDU2_VOICE13); - m_dfsiLC.decodeLDU2(data + count, m_netLDU2 + 80U); - count += 17U; - - m_dfsiLC.setFrameType(dfsi::P25_DFSI_LDU2_VOICE14); - m_dfsiLC.decodeLDU2(data + count, m_netLDU2 + 105U); - count += 17U; - - m_dfsiLC.setFrameType(dfsi::P25_DFSI_LDU2_VOICE15); - m_dfsiLC.decodeLDU2(data + count, m_netLDU2 + 130U); - count += 17U; - - m_dfsiLC.setFrameType(dfsi::P25_DFSI_LDU2_VOICE16); - m_dfsiLC.decodeLDU2(data + count, m_netLDU2 + 155U); - count += 17U; - - m_dfsiLC.setFrameType(dfsi::P25_DFSI_LDU2_VOICE17); - m_dfsiLC.decodeLDU2(data + count, m_netLDU2 + 180U); - count += 17U; - - m_dfsiLC.setFrameType(dfsi::P25_DFSI_LDU2_VOICE18); - m_dfsiLC.decodeLDU2(data + count, m_netLDU2 + 204U); - count += 16U; - - if (m_p25->m_netState == RS_NET_IDLE) { - if (!m_p25->m_voiceOnControl) { - m_p25->m_modem->clearP25Frame(); - } - m_p25->m_txQueue.clear(); - - resetRF(); - resetNet(); - - writeNet_LDU1(); - } - else { - checkNet_LDU1(); - } - - if (m_p25->m_netState != RS_NET_IDLE) { - writeNet_LDU2(); - } - } - break; - case P25_DUID_TDU: - case P25_DUID_TDULC: - // don't process network frames if the RF modem isn't in a listening state - if (m_p25->m_rfState != RS_RF_LISTENING) { - resetNet(); - return false; - } - - if (!m_p25->m_control) { - m_p25->m_affiliations.releaseGrant(m_netLC.getDstId(), false); - m_p25->notifyCC_ReleaseGrant(m_netLC.getDstId()); - } - - if (m_p25->m_netState != RS_NET_IDLE) { - if (duid == P25_DUID_TDU) - writeNet_TDU(); - - resetNet(); - } - break; - } - - return true; -} - -// --------------------------------------------------------------------------- -// Protected Class Members -// --------------------------------------------------------------------------- - -/// -/// Initializes a new instance of the DFSIVoice class. -/// -/// Instance of the Control class. -/// Instance of the BaseNetwork class. -/// Flag indicating whether P25 debug is enabled. -/// Flag indicating whether P25 verbose logging is enabled. -DFSIVoice::DFSIVoice(Control* p25, network::BaseNetwork* network, bool debug, bool verbose) : - Voice(p25, network, debug, verbose), - m_trunk(nullptr), - m_rfDFSILC(), - m_netDFSILC(), - m_dfsiLDU1(nullptr), - m_dfsiLDU2(nullptr) -{ - m_dfsiLDU1 = new uint8_t[9U * 25U]; - m_dfsiLDU2 = new uint8_t[9U * 25U]; - - ::memset(m_dfsiLDU1, 0x00U, 9U * 25U); - ::memset(m_dfsiLDU2, 0x00U, 9U * 25U); - - // hmmm...this should hopefully be a safe cast...right? - m_trunk = (DFSITrunk *)p25->m_trunk; -} - -/// -/// Finalizes a instance of the DFSIVoice class. -/// -DFSIVoice::~DFSIVoice() -{ - delete[] m_dfsiLDU1; - delete[] m_dfsiLDU2; -} - -/// -/// Helper to write a network P25 TDU packet. -/// -void DFSIVoice::writeNet_TDU() -{ - m_trunk->writeRF_DSFI_Stop(P25_DFSI_TYPE_VOICE); - - if (m_verbose) { - LogMessage(LOG_NET, P25_TDU_STR ", srcId = %u", m_netLC.getSrcId()); - } - - if (m_netFrames > 0) { - ::ActivityLog("P25", false, "network end of transmission, %.1f seconds, %u%% packet loss", - float(m_netFrames) / 50.0F, (m_netLost * 100U) / m_netFrames); - } - else { - ::ActivityLog("P25", false, "network end of transmission, %u frames", m_netFrames); - } - - if (m_network != nullptr) - m_network->resetP25(); - - ::memset(m_netLDU1, 0x00U, 9U * 25U); - ::memset(m_netLDU2, 0x00U, 9U * 25U); - - m_p25->m_netTimeout.stop(); - m_p25->m_networkWatchdog.stop(); - resetNet(); - m_p25->m_netState = RS_NET_IDLE; - m_p25->m_netLastDstId = 0U; - m_p25->m_tailOnIdle = true; -} - -/// -/// Helper to write a network P25 LDU1 packet. -/// -/// -/// -void DFSIVoice::writeNet_LDU1() -{ - lc::LC control = lc::LC(*m_dfsiLC.control()); - data::LowSpeedData lsd = data::LowSpeedData(*m_dfsiLC.lsd()); - - uint32_t dstId = control.getDstId(); - uint32_t srcId = control.getSrcId(); - bool group = control.getLCO() == LC_GROUP; - - // ensure our srcId and dstId are sane from the last LDU1 - if (m_netLastLDU1.getDstId() != 0U) { - if (dstId != m_netLastLDU1.getDstId()) { - LogWarning(LOG_NET, P25_HDU_STR ", dstId = %u doesn't match last LDU1 dstId = %u, fixing", - m_rfLC.getDstId(), m_rfLastLDU1.getDstId()); - dstId = m_netLastLDU1.getDstId(); - } - } - else { - LogWarning(LOG_NET, P25_HDU_STR ", last LDU1 LC has bad data, dstId = 0"); - } - - if (m_netLastLDU1.getSrcId() != 0U) { - if (srcId != m_netLastLDU1.getSrcId()) { - LogWarning(LOG_NET, P25_HDU_STR ", srcId = %u doesn't match last LDU1 srcId = %u, fixing", - m_rfLC.getSrcId(), m_rfLastLDU1.getSrcId()); - srcId = m_netLastLDU1.getSrcId(); - } - } - else { - LogWarning(LOG_NET, P25_HDU_STR ", last LDU1 LC has bad data, srcId = 0"); - } - - // don't process network frames if the destination ID's don't match and the network TG hang timer is running - if (m_p25->m_rfLastDstId != 0U) { - if (m_p25->m_rfLastDstId != dstId && (m_p25->m_rfTGHang.isRunning() && !m_p25->m_rfTGHang.hasExpired())) { - resetNet(); - return; - } - - if (m_p25->m_rfLastDstId == dstId && (m_p25->m_rfTGHang.isRunning() && !m_p25->m_rfTGHang.hasExpired())) { - m_p25->m_rfTGHang.start(); - } - } - - // don't process network frames if the RF modem isn't in a listening state - if (m_p25->m_rfState != RS_RF_LISTENING) { - if (m_rfLC.getSrcId() == srcId && m_rfLC.getDstId() == dstId) { - LogWarning(LOG_RF, "Traffic collision detect, preempting new network traffic to existing RF traffic (Are we in a voting condition?), rfSrcId = %u, rfDstId = %u, netSrcId = %u, netDstId = %u", m_rfLC.getSrcId(), m_rfLC.getDstId(), - srcId, dstId); - resetNet(); - return; - } - else { - LogWarning(LOG_RF, "Traffic collision detect, preempting new network traffic to existing RF traffic, rfDstId = %u, netDstId = %u", m_rfLC.getDstId(), - dstId); - resetNet(); - return; - } - } - - if (m_p25->m_control) { - m_p25->m_affiliations.touchGrant(m_rfLC.getDstId()); - m_p25->notifyCC_TouchGrant(m_rfLC.getDstId()); - } - - // set network and RF link control states - m_netLC = lc::LC(); - m_netLC.setLCO(control.getLCO()); - m_netLC.setMFId(control.getMFId()); - m_netLC.setSrcId(srcId); - m_netLC.setDstId(dstId); - m_netLC.setGroup(group); - m_netLC.setEmergency(control.getEmergency()); - m_netLC.setEncrypted(control.getEncrypted()); - m_netLC.setPriority(control.getPriority()); - - m_rfLC = lc::LC(); - m_rfLC.setLCO(control.getLCO()); - m_rfLC.setMFId(control.getMFId()); - m_rfLC.setSrcId(srcId); - m_rfLC.setDstId(dstId); - m_rfLC.setGroup(group); - m_rfLC.setEmergency(control.getEmergency()); - m_rfLC.setEncrypted(control.getEncrypted()); - m_rfLC.setPriority(control.getPriority()); - - // if we are idle lets generate HDU data - if (m_p25->m_netState == RS_NET_IDLE) { - uint8_t mi[P25_MI_LENGTH_BYTES]; - control.getMI(mi); - - if (m_verbose && m_debug) { - Utils::dump(1U, "Network HDU MI", mi, P25_MI_LENGTH_BYTES); - } - - m_netLC.setMI(mi); - m_rfLC.setMI(mi); - m_netLC.setAlgId(control.getAlgId()); - m_rfLC.setAlgId(control.getAlgId()); - m_netLC.setKId(control.getKId()); - m_rfLC.setKId(control.getKId()); - - // validate source RID - if (!acl::AccessControl::validateSrcId(srcId)) { - LogWarning(LOG_NET, P25_HDU_STR " denial, RID rejection, srcId = %u", srcId); - return; - } - - // is this a group or individual operation? - if (!group) { - // validate the target RID - if (!acl::AccessControl::validateSrcId(dstId)) { - LogWarning(LOG_NET, P25_HDU_STR " denial, RID rejection, dstId = %u", dstId); - return; - } - } - else { - // validate the target ID, if the target is a talkgroup - if (!acl::AccessControl::validateTGId(dstId)) { - LogWarning(LOG_NET, P25_HDU_STR " denial, TGID rejection, dstId = %u", dstId); - return; - } - } - - ::ActivityLog("P25", false, "network %svoice transmission from %u to %s%u", m_netLC.getEncrypted() ? "encrypted " : "", srcId, group ? "TG " : "", dstId); - - uint8_t serviceOptions = (m_rfLC.getEmergency() ? 0x80U : 0x00U) + // Emergency Flag - (m_rfLC.getEncrypted() ? 0x40U : 0x00U) + // Encrypted Flag - (m_rfLC.getPriority() & 0x07U); // Priority - - // single-channel trunking or voice on control support? - if (m_p25->m_control && m_p25->m_voiceOnControl) { - if (!m_p25->m_trunk->writeRF_TSDU_Grant(srcId, dstId, serviceOptions, group, false, true)) { - if (m_network != nullptr) - m_network->resetP25(); - - ::memset(m_netLDU1, 0x00U, 9U * 25U); - ::memset(m_netLDU2, 0x00U, 9U * 25U); - - m_p25->m_netTimeout.stop(); - m_p25->m_networkWatchdog.stop(); - - m_netLC = lc::LC(); - m_netLastLDU1 = lc::LC(); - - m_p25->m_netState = RS_NET_IDLE; - m_p25->m_netLastDstId = 0U; - - if (m_p25->m_rfState == RS_RF_REJECTED) { - m_p25->m_rfState = RS_RF_LISTENING; - } - - return; - } - - m_p25->writeRF_Preamble(0, true); - } - - m_hadVoice = true; - m_p25->m_netState = RS_NET_AUDIO; - m_p25->m_netLastDstId = dstId; - m_p25->m_netTimeout.start(); - m_netFrames = 0U; - m_netLost = 0U; - m_vocLDU1Count = 0U; - - m_netDFSILC = dfsi::LC(m_netLC, lsd); - - m_trunk->writeRF_DFSI_Start(P25_DFSI_TYPE_VOICE); - - uint8_t buffer[P25_DFSI_VHDR1_FRAME_LENGTH_BYTES + 2U]; - ::memset(buffer, 0x00U, P25_DFSI_VHDR1_FRAME_LENGTH_BYTES + 2U); - - // Generate Voice Header 1 - m_netDFSILC.setFrameType(P25_DFSI_VHDR1); - m_netDFSILC.encodeVHDR1(buffer + 2U); - - buffer[0U] = modem::TAG_DATA; - buffer[1U] = 0x00U; - m_p25->addFrame(buffer, P25_DFSI_VHDR1_FRAME_LENGTH_BYTES + 2U, true); - - // Generate Voice Header 2 - m_netDFSILC.setFrameType(P25_DFSI_VHDR2); - m_netDFSILC.encodeVHDR2(buffer + 2U); - - buffer[0U] = modem::TAG_DATA; - buffer[1U] = 0x00U; - m_p25->addFrame(buffer, P25_DFSI_VHDR2_FRAME_LENGTH_BYTES + 2U, true); - - if (m_verbose) { - LogMessage(LOG_NET, P25_HDU_STR " DFSI, dstId = %u, algo = $%02X, kid = $%04X", m_netLC.getDstId(), m_netLC.getAlgId(), m_netLC.getKId()); - } - } - - // single-channel trunking or voice on control support? - if (m_p25->m_control && 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) { - m_vocLDU1Count = 0U; - m_netLC.setLCO(LC_RFSS_STS_BCAST); - } - } - - insertMissingAudio(m_netLDU1); - - uint8_t buffer[P25_DFSI_LDU1_VOICE1_FRAME_LENGTH_BYTES + 2U]; - for (uint8_t i = P25_DFSI_LDU1_VOICE1; i <= P25_DFSI_LDU1_VOICE9; i++) { - uint8_t len = P25_DFSI_LDU1_VOICE1_FRAME_LENGTH_BYTES; - - // frame 2 - if (i == P25_DFSI_LDU1_VOICE2) { - len = P25_DFSI_LDU1_VOICE2_FRAME_LENGTH_BYTES; - } - - // frames 3 - 8 are the same size - if (i >= P25_DFSI_LDU1_VOICE3_FRAME_LENGTH_BYTES && i <= P25_DFSI_LDU1_VOICE8_FRAME_LENGTH_BYTES) { - len = P25_DFSI_LDU1_VOICE3_FRAME_LENGTH_BYTES; - } - - // frame 9 - if (i == P25_DFSI_LDU1_VOICE9) { - len = P25_DFSI_LDU1_VOICE9_FRAME_LENGTH_BYTES; - } - - uint8_t n = 10U; - switch (i) { - case P25_DFSI_LDU1_VOICE1: - n = 10U; - break; - case P25_DFSI_LDU1_VOICE2: - n = 26U; - break; - case P25_DFSI_LDU1_VOICE3: - n = 55U; - break; - case P25_DFSI_LDU1_VOICE4: - n = 80U; - break; - case P25_DFSI_LDU1_VOICE5: - n = 105U; - break; - case P25_DFSI_LDU1_VOICE6: - n = 130U; - break; - case P25_DFSI_LDU1_VOICE7: - n = 155U; - break; - case P25_DFSI_LDU1_VOICE8: - n = 180U; - break; - case P25_DFSI_LDU1_VOICE9: - n = 204U; - break; - } - - ::memset(buffer, 0x00U, len + 2U); - - // Generate Voice Frame - m_netDFSILC.setFrameType(i); - m_netDFSILC.encodeLDU1(buffer + 2U, m_netLDU1 + n); - - buffer[0U] = modem::TAG_DATA; - buffer[1U] = 0x00U; - - m_p25->addFrame(buffer, len + 2U, true); - } - - if (m_verbose) { - uint32_t loss = 0; - if (m_netFrames != 0) { - loss = (m_netLost * 100U) / m_netFrames; - } - else { - loss = (m_netLost * 100U) / 1U; - if (loss > 100) { - loss = 100; - } - } - - LogMessage(LOG_NET, P25_LDU1_STR " DFSI audio, srcId = %u, dstId = %u, group = %u, emerg = %u, encrypt = %u, prio = %u, %u%% packet loss", - m_netLC.getSrcId(), m_netLC.getDstId(), m_netLC.getGroup(), m_netLC.getEmergency(), m_netLC.getEncrypted(), m_netLC.getPriority(), loss); - } - - ::memset(m_netLDU1, 0x00U, 9U * 25U); - - m_netFrames += 9U; -} - -/// -/// Helper to write a network P25 LDU2 packet. -/// -/// -/// -void DFSIVoice::writeNet_LDU2() -{ - lc::LC control = lc::LC(*m_dfsiLC.control()); - data::LowSpeedData lsd = data::LowSpeedData(*m_dfsiLC.lsd()); - - // don't process network frames if the destination ID's don't match and the network TG hang timer is running - if (m_p25->m_rfLastDstId != 0U) { - if (m_p25->m_rfLastDstId != m_netLastLDU1.getDstId() && (m_p25->m_rfTGHang.isRunning() && !m_p25->m_rfTGHang.hasExpired())) { - resetNet(); - return; - } - } - - uint8_t mi[P25_MI_LENGTH_BYTES]; - control.getMI(mi); - - if (m_verbose && m_debug) { - Utils::dump(1U, "Network LDU2 MI", mi, P25_MI_LENGTH_BYTES); - } - - m_netLC.setMI(mi); - m_netLC.setAlgId(control.getAlgId()); - m_netLC.setKId(control.getKId()); - - m_netDFSILC.setControl(m_netLC); - - insertMissingAudio(m_netLDU2); - - uint8_t buffer[P25_DFSI_LDU2_VOICE10_FRAME_LENGTH_BYTES + 2U]; - for (uint8_t i = P25_DFSI_LDU2_VOICE10; i <= P25_DFSI_LDU2_VOICE18; i++) { - uint8_t len = P25_DFSI_LDU2_VOICE10_FRAME_LENGTH_BYTES; - - // frame 11 - if (i == P25_DFSI_LDU2_VOICE11) { - len = P25_DFSI_LDU2_VOICE11_FRAME_LENGTH_BYTES; - } - - // frames 12 - 17 are the same size - if (i >= P25_DFSI_LDU2_VOICE12_FRAME_LENGTH_BYTES && i <= P25_DFSI_LDU2_VOICE17_FRAME_LENGTH_BYTES) { - len = P25_DFSI_LDU2_VOICE12_FRAME_LENGTH_BYTES; - } - - // frame 9 - if (i == P25_DFSI_LDU2_VOICE18) { - len = P25_DFSI_LDU2_VOICE18_FRAME_LENGTH_BYTES; - } - - uint8_t n = 10U; - switch (i) { - case P25_DFSI_LDU2_VOICE10: - n = 10U; - break; - case P25_DFSI_LDU2_VOICE11: - n = 26U; - break; - case P25_DFSI_LDU2_VOICE12: - n = 55U; - break; - case P25_DFSI_LDU2_VOICE13: - n = 80U; - break; - case P25_DFSI_LDU2_VOICE14: - n = 105U; - break; - case P25_DFSI_LDU2_VOICE15: - n = 130U; - break; - case P25_DFSI_LDU2_VOICE16: - n = 155U; - break; - case P25_DFSI_LDU2_VOICE17: - n = 180U; - break; - case P25_DFSI_LDU2_VOICE18: - n = 204U; - break; - } - - ::memset(buffer, 0x00U, len + 2U); - - // Generate Voice Frame - m_netDFSILC.setFrameType(i); - m_netDFSILC.encodeLDU2(buffer + 2U, m_netLDU2 + n); - - buffer[0U] = modem::TAG_DATA; - buffer[1U] = 0x00U; - - m_p25->addFrame(buffer, len + 2U, true); - } - - if (m_verbose) { - uint32_t loss = 0; - if (m_netFrames != 0) { - loss = (m_netLost * 100U) / m_netFrames; - } - else { - loss = (m_netLost * 100U) / 1U; - if (loss > 100) { - loss = 100; - } - } - - LogMessage(LOG_NET, P25_LDU2_STR " audio, algo = $%02X, kid = $%04X, %u%% packet loss", m_netLC.getAlgId(), m_netLC.getKId(), loss); - } - - ::memset(m_netLDU2, 0x00U, 9U * 25U); - - m_netFrames += 9U; -} diff --git a/src/p25/dfsi/packet/DFSIVoice.h b/src/p25/dfsi/packet/DFSIVoice.h deleted file mode 100644 index 3fa826ea..00000000 --- a/src/p25/dfsi/packet/DFSIVoice.h +++ /dev/null @@ -1,99 +0,0 @@ -/** -* 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 -* -*/ -// -// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost) -// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0) -// -/* -* Copyright (C) 2022 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_DFSI_PACKET_VOICE_H__) -#define __P25_DFSI_PACKET_VOICE_H__ - -#include "Defines.h" -#include "p25/dfsi/LC.h" -#include "p25/dfsi/packet/DFSITrunk.h" -#include "p25/Control.h" -#include "network/BaseNetwork.h" - -namespace p25 -{ - // --------------------------------------------------------------------------- - // Class Prototypes - // --------------------------------------------------------------------------- - - namespace packet { class HOST_SW_API Voice; } - class HOST_SW_API Control; - - namespace dfsi - { - namespace packet - { - // --------------------------------------------------------------------------- - // Class Declaration - // This class implements handling logic for P25 voice packets using - // the DFSI protocol instead of the P25 OTA protocol. - // --------------------------------------------------------------------------- - - class HOST_SW_API DFSIVoice : public p25::packet::Voice { - public: - /// Resets the data states for the RF interface. - void resetRF() override; - /// Resets the data states for the network. - void resetNet() override; - - /// Process a data frame from the RF interface. - bool process(uint8_t* data, uint32_t len) override; - /// Process a data frame from the network. - bool processNetwork(uint8_t* data, uint32_t len, lc::LC& control, data::LowSpeedData& lsd, uint8_t& duid, uint8_t& frameType) override; - - protected: - DFSITrunk* m_trunk; - - LC m_rfDFSILC; - LC m_netDFSILC; - - uint8_t* m_dfsiLDU1; - uint8_t* m_dfsiLDU2; - - /// Initializes a new instance of the DFSIVoice class. - DFSIVoice(Control* p25, network::BaseNetwork* network, bool debug, bool verbose); - /// Finalizes a instance of the DFSIVoice class. - virtual ~DFSIVoice(); - - /// Helper to write a network P25 TDU packet. - void writeNet_TDU() override; - /// Helper to write a network P25 LDU1 packet. - void writeNet_LDU1() override; - /// Helper to write a network P25 LDU1 packet. - void writeNet_LDU2() override; - - private: - friend class packet::DFSITrunk; - friend class p25::Control; - }; - } // namespace packet - } // namespace dfsi -} // namespace p25 - -#endif // __P25_DFSI_PACKET_VOICE_H__ diff --git a/src/p25/packet/Trunk.h b/src/p25/packet/Trunk.h index 0b59f4b0..6769b479 100644 --- a/src/p25/packet/Trunk.h +++ b/src/p25/packet/Trunk.h @@ -48,7 +48,6 @@ namespace p25 // --------------------------------------------------------------------------- namespace packet { class HOST_SW_API Voice; } - namespace dfsi { namespace packet { class HOST_SW_API DFSIVoice; } } namespace packet { class HOST_SW_API Data; } namespace lookups { class HOST_SW_API P25AffiliationLookup; } class HOST_SW_API Control; @@ -104,7 +103,6 @@ namespace p25 protected: friend class packet::Voice; - friend class dfsi::packet::DFSIVoice; friend class packet::Data; friend class p25::Control; Control* m_p25;